fastify 5.8.5 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROJECT_CHARTER.md +1 -1
- package/README.md +7 -10
- package/SECURITY.md +1 -1
- package/SPONSORS.md +6 -4
- package/build/build-validation.js +2 -2
- package/docs/Guides/Database.md +0 -28
- package/docs/Guides/Delay-Accepting-Requests.md +1 -1
- package/docs/Guides/Ecosystem.md +23 -9
- package/docs/Guides/Getting-Started.md +2 -2
- package/docs/Guides/Migration-Guide-V4.md +2 -2
- package/docs/Guides/Migration-Guide-V5.md +1 -1
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Prototype-Poisoning.md +3 -3
- package/docs/Guides/Serverless.md +8 -15
- package/docs/Guides/Style-Guide.md +1 -1
- package/docs/Guides/Write-Plugin.md +1 -1
- package/docs/Reference/Encapsulation.md +27 -26
- package/docs/Reference/Errors.md +12 -4
- package/docs/Reference/HTTP2.md +10 -10
- package/docs/Reference/Hooks.md +5 -5
- package/docs/Reference/Index.md +14 -16
- package/docs/Reference/LTS.md +12 -13
- package/docs/Reference/Lifecycle.md +9 -8
- package/docs/Reference/Logging.md +47 -39
- package/docs/Reference/Middleware.md +21 -25
- package/docs/Reference/Principles.md +2 -2
- package/docs/Reference/Reply.md +6 -1
- package/docs/Reference/Request.md +29 -18
- package/docs/Reference/Routes.md +5 -2
- package/docs/Reference/Server.md +138 -11
- package/docs/Reference/Type-Providers.md +53 -9
- package/docs/Reference/TypeScript.md +3 -3
- package/docs/Reference/Validation-and-Serialization.md +15 -2
- package/docs/Reference/Warnings.md +11 -6
- package/eslint.config.js +7 -2
- package/fastify.d.ts +13 -3
- package/fastify.js +60 -31
- package/lib/content-type-parser.js +2 -0
- package/lib/content-type.js +34 -1
- package/lib/context.js +0 -3
- package/lib/decorate.js +11 -3
- package/lib/error-handler.js +10 -28
- package/lib/error-serializer.js +59 -59
- package/lib/errors.js +23 -1
- package/lib/four-oh-four.js +22 -19
- package/lib/handle-request.js +12 -5
- package/lib/log-controller.js +169 -0
- package/lib/logger-factory.js +25 -4
- package/lib/plugin-override.js +2 -1
- package/lib/plugin-utils.js +5 -5
- package/lib/reply.js +96 -50
- package/lib/req-id-gen-factory.js +4 -1
- package/lib/request.js +16 -6
- package/lib/route.js +47 -41
- package/lib/schema-controller.js +1 -1
- package/lib/schemas.js +37 -30
- package/lib/symbols.js +4 -2
- package/lib/validation.js +10 -13
- package/lib/warnings.js +22 -4
- package/package.json +15 -17
- package/scripts/validate-ecosystem-links.js +1 -0
- package/test/bundler/esbuild/package.json +1 -1
- package/test/close-pipelining.test.js +1 -2
- package/test/content-type.test.js +20 -0
- package/test/custom-http-server.test.js +38 -0
- package/test/decorator-instance-properties.test.js +63 -0
- package/test/diagnostics-channel/async-error-handler.test.js +74 -0
- package/test/genReqId.test.js +24 -0
- package/test/hooks.test.js +94 -0
- package/test/http-methods/get.test.js +1 -1
- package/test/http2/plain.test.js +135 -0
- package/test/http2/secure-with-fallback.test.js +1 -1
- package/test/https/https.test.js +1 -2
- package/test/internals/errors.test.js +31 -1
- package/test/internals/logger.test.js +322 -0
- package/test/internals/plugin.test.js +3 -1
- package/test/internals/reply.test.js +35 -4
- package/test/internals/request.test.js +37 -10
- package/test/internals/schema-controller-perf.test.js +33 -0
- package/test/logger/logging.test.js +57 -1
- package/test/logger/options.test.js +38 -1
- package/test/reply-error.test.js +1 -1
- package/test/reply-trailers.test.js +70 -0
- package/test/request-media-type.test.js +105 -0
- package/test/route-prefix.test.js +34 -0
- package/test/router-options.test.js +222 -11
- package/test/schema-serialization.test.js +108 -0
- package/test/schema-validation.test.js +24 -0
- package/test/scripts/validate-ecosystem-links.test.js +40 -57
- package/test/stream.4.test.js +2 -2
- package/test/throw.test.js +14 -0
- package/test/trust-proxy.test.js +70 -30
- package/test/types/content-type-parser.tst.ts +70 -0
- package/test/types/{decorate-request-reply.test-d.ts → decorate-request-reply.tst.ts} +4 -4
- package/test/types/{dummy-plugin.ts → dummy-plugin.mts} +1 -1
- package/test/types/errors.tst.ts +91 -0
- package/test/types/fastify.tst.ts +351 -0
- package/test/types/hooks.tst.ts +578 -0
- package/test/types/instance.tst.ts +597 -0
- package/test/types/{logger.test-d.ts → logger.tst.ts} +61 -62
- package/test/types/plugin.tst.ts +96 -0
- package/test/types/register.tst.ts +245 -0
- package/test/types/reply.tst.ts +297 -0
- package/test/types/request.tst.ts +199 -0
- package/test/types/route.tst.ts +576 -0
- package/test/types/{schema.test-d.ts → schema.tst.ts} +22 -22
- package/test/types/{serverFactory.test-d.ts → serverFactory.tst.ts} +4 -4
- package/test/types/tsconfig.json +9 -0
- package/test/types/{type-provider.test-d.ts → type-provider.tst.ts} +256 -250
- package/test/types/using.tst.ts +14 -0
- package/types/errors.d.ts +4 -0
- package/types/instance.d.ts +2 -0
- package/types/logger.d.ts +22 -0
- package/types/request.d.ts +23 -2
- package/test/types/content-type-parser.test-d.ts +0 -72
- package/test/types/errors.test-d.ts +0 -90
- package/test/types/fastify.test-d.ts +0 -352
- package/test/types/hooks.test-d.ts +0 -550
- package/test/types/import.ts +0 -2
- package/test/types/instance.test-d.ts +0 -588
- package/test/types/plugin.test-d.ts +0 -97
- package/test/types/register.test-d.ts +0 -237
- package/test/types/reply.test-d.ts +0 -254
- package/test/types/request.test-d.ts +0 -188
- package/test/types/route.test-d.ts +0 -553
- package/test/types/using.test-d.ts +0 -17
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Every decision in the Fastify framework and its official plugins is guided by
|
|
4
4
|
the following technical principles:
|
|
5
5
|
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
6
|
+
1. "Zero" overhead in production
|
|
7
|
+
2. "Good" developer experience
|
|
8
8
|
3. Works great for small & big projects alike
|
|
9
9
|
4. Easy to migrate to microservices (or even serverless) and back
|
|
10
10
|
5. Security & data validation
|
package/docs/Reference/Reply.md
CHANGED
|
@@ -219,7 +219,7 @@ reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
|
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
### .removeHeader(key)
|
|
222
|
-
<a id="
|
|
222
|
+
<a id="removeHeader"></a>
|
|
223
223
|
|
|
224
224
|
Remove the value of a previously set header.
|
|
225
225
|
```js
|
|
@@ -705,6 +705,11 @@ If you are sending a stream and you have not set a `'Content-Type'` header,
|
|
|
705
705
|
As noted above, streams are considered to be pre-serialized, so they will be
|
|
706
706
|
sent unmodified without response validation.
|
|
707
707
|
|
|
708
|
+
When sending streams over HTTP/2, Fastify does not change the chunks emitted by
|
|
709
|
+
the stream. If a stream can emit very large chunks, split them in your
|
|
710
|
+
application code, for example by using `fs.createReadStream()` or a transform
|
|
711
|
+
stream that emits smaller chunks.
|
|
712
|
+
|
|
708
713
|
See special note about error handling for streams in
|
|
709
714
|
[`setErrorHandler`](./Server.md#seterrorhandler).
|
|
710
715
|
|
|
@@ -16,28 +16,39 @@ Request is a core Fastify object containing the following fields:
|
|
|
16
16
|
[encapsulation context](./Encapsulation.md).
|
|
17
17
|
- `id` - The request ID.
|
|
18
18
|
- `log` - The logger instance of the incoming request.
|
|
19
|
-
- `ip` - The IP address of the incoming request.
|
|
20
|
-
|
|
21
|
-
`
|
|
22
|
-
|
|
19
|
+
- `ip` - The IP address of the incoming request. This value is taken from
|
|
20
|
+
`socket.remoteAddress` (or from `X-Forwarded-For` when
|
|
21
|
+
[`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
|
|
22
|
+
- `ips` - An array of IP addresses, ordered from closest to furthest, from
|
|
23
|
+
`X-Forwarded-For` (only when
|
|
24
|
+
[`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
|
|
23
25
|
- `host` - The host of the incoming request (derived from `X-Forwarded-Host`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
No additional validation is performed beyond RFC parsing (see
|
|
31
|
-
[RFC 9110, section 7.2](https://www.rfc-editor.org/rfc/rfc9110#section-7.2) and
|
|
32
|
-
[RFC 3986, section 3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2)).
|
|
33
|
-
- `hostname` - The hostname derived from the `host` property of the incoming request.
|
|
34
|
-
- `port` - The port from the `host` property, which may refer to the port the
|
|
26
|
+
when [`trustProxy`](./Server.md#factory-trust-proxy) is enabled). For HTTP/2
|
|
27
|
+
compatibility, it returns `:authority` if no host header exists. The host
|
|
28
|
+
header may return an empty string if `requireHostHeader` is `false`, not
|
|
29
|
+
provided with HTTP/1.0, or removed by schema validation.
|
|
30
|
+
- `hostname` - The hostname parsed from `request.host`.
|
|
31
|
+
- `port` - The port parsed from `request.host`, which may refer to the port the
|
|
35
32
|
server is listening on.
|
|
36
|
-
- `protocol` - The protocol of the incoming request (`https` or `http`).
|
|
33
|
+
- `protocol` - The protocol of the incoming request (`https` or `http`). This
|
|
34
|
+
value comes from `socket.encrypted` (or `X-Forwarded-Proto` when
|
|
35
|
+
[`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
|
|
36
|
+
|
|
37
|
+
> ⚠️ Security:
|
|
38
|
+
> `request.ip`, `request.ips`, `request.host`, `request.hostname`,
|
|
39
|
+
> `request.port`, and `request.protocol` come from request metadata
|
|
40
|
+
> (socket and/or forwarding headers) and should be treated as untrusted input.
|
|
41
|
+
> Fastify does not perform security validation for business logic.
|
|
42
|
+
> If these values are used in security-sensitive decisions, they must
|
|
43
|
+
> be validated explicitly (for example: trusted proxy configuration,
|
|
44
|
+
> allow-lists, strict parsing, and normalization).
|
|
45
|
+
|
|
37
46
|
- `method` - The method of the incoming request.
|
|
38
47
|
- `url` - The URL of the incoming request.
|
|
39
48
|
- `originalUrl` - Similar to `url`, allows access to the original `url` in
|
|
40
49
|
case of internal re-routing.
|
|
50
|
+
- `mediaType` - The media type extracted from `Content-Type` header. When `Content-Type`
|
|
51
|
+
header is missing, it will return `undefined`.
|
|
41
52
|
- `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
|
|
42
53
|
- `socket` - The underlying connection of the incoming request.
|
|
43
54
|
- `signal` - An `AbortSignal` that aborts when the handler timeout
|
|
@@ -121,14 +132,14 @@ fastify.post('/:params', options, function (request, reply) {
|
|
|
121
132
|
console.log(request.url)
|
|
122
133
|
console.log(request.routeOptions.method)
|
|
123
134
|
console.log(request.routeOptions.bodyLimit)
|
|
124
|
-
console.log(request.routeOptions.
|
|
135
|
+
console.log(request.routeOptions.handlerTimeout)
|
|
125
136
|
console.log(request.routeOptions.url)
|
|
126
137
|
console.log(request.routeOptions.attachValidation)
|
|
127
138
|
console.log(request.routeOptions.logLevel)
|
|
128
139
|
console.log(request.routeOptions.version)
|
|
129
140
|
console.log(request.routeOptions.exposeHeadRoute)
|
|
130
141
|
console.log(request.routeOptions.prefixTrailingSlash)
|
|
131
|
-
console.log(request.routeOptions.
|
|
142
|
+
console.log(request.routeOptions.config)
|
|
132
143
|
request.log.info('some info')
|
|
133
144
|
})
|
|
134
145
|
```
|
package/docs/Reference/Routes.md
CHANGED
|
@@ -102,7 +102,7 @@ fastify.route(options)
|
|
|
102
102
|
schemas for request validations. See the [Validation and
|
|
103
103
|
Serialization](./Validation-and-Serialization.md#schema-validator)
|
|
104
104
|
documentation.
|
|
105
|
-
* `serializerCompiler({
|
|
105
|
+
* `serializerCompiler({ schema, method, url, httpStatus, contentType })`:
|
|
106
106
|
function that builds schemas for response serialization. See the [Validation and
|
|
107
107
|
Serialization](./Validation-and-Serialization.md#schema-serializer)
|
|
108
108
|
documentation.
|
|
@@ -513,6 +513,9 @@ See the `prefixTrailingSlash` route option above to change this behavior.
|
|
|
513
513
|
Different log levels can be set for routes in Fastify by passing the `logLevel`
|
|
514
514
|
option to the plugin or route with the desired
|
|
515
515
|
[value](https://github.com/pinojs/pino/blob/main/docs/api.md#level-string).
|
|
516
|
+
If a route `logLevel` is invalid, Fastify throws
|
|
517
|
+
[`FST_ERR_ROUTE_LOG_LEVEL_INVALID`](./Errors.md#fst_err_route_log_level_invalid)
|
|
518
|
+
during route registration.
|
|
516
519
|
|
|
517
520
|
Be aware that setting `logLevel` at the plugin level also affects
|
|
518
521
|
[`setNotFoundHandler`](./Server.md#setnotfoundhandler) and
|
|
@@ -670,7 +673,7 @@ fastify.inject({
|
|
|
670
673
|
|
|
671
674
|
> ⚠ Warning:
|
|
672
675
|
> Set a
|
|
673
|
-
> [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary)
|
|
676
|
+
> [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Vary)
|
|
674
677
|
> header in responses with the value used for versioning
|
|
675
678
|
> (e.g., `'Accept-Version'`) to prevent cache poisoning attacks.
|
|
676
679
|
> This can also be configured in a Proxy/CDN.
|
package/docs/Reference/Server.md
CHANGED
|
@@ -23,6 +23,7 @@ describes the properties available in that options object.
|
|
|
23
23
|
- [`logger`](#logger)
|
|
24
24
|
- [`loggerInstance`](#loggerinstance)
|
|
25
25
|
- [`disableRequestLogging`](#disablerequestlogging)
|
|
26
|
+
- [`logController`](#logcontroller)
|
|
26
27
|
- [`serverFactory`](#serverfactory)
|
|
27
28
|
- [`requestIdHeader`](#requestidheader)
|
|
28
29
|
- [`requestIdLogLabel`](#requestidloglabel)
|
|
@@ -48,6 +49,7 @@ describes the properties available in that options object.
|
|
|
48
49
|
- [`ignoreTrailingSlash`](#ignoretrailingslash)
|
|
49
50
|
- [`maxParamLength`](#maxparamlength)
|
|
50
51
|
- [`onBadUrl`](#onbadurl)
|
|
52
|
+
- [`onMaxParamLength`](#onmaxparamlength)
|
|
51
53
|
- [`querystringParser`](#querystringparser)
|
|
52
54
|
- [`useSemicolonDelimiter`](#usesemicolondelimiter)
|
|
53
55
|
- [Instance](#instance)
|
|
@@ -388,6 +390,10 @@ Pino interface by having the following methods: `info`, `error`, `debug`,
|
|
|
388
390
|
### `disableRequestLogging`
|
|
389
391
|
<a id="factory-disable-request-logging"></a>
|
|
390
392
|
|
|
393
|
+
> **Deprecated:** Use the [`logController`](#log-controller) option with
|
|
394
|
+
> `disableRequestLogging` or `isLogDisabled` override instead.
|
|
395
|
+
> This top-level option will be removed in `fastify@6`.
|
|
396
|
+
|
|
391
397
|
+ Default: `false`
|
|
392
398
|
|
|
393
399
|
When logging is enabled, Fastify will issue an `info` level log
|
|
@@ -401,13 +407,23 @@ and returns a boolean. This allows for conditional request logging based on the
|
|
|
401
407
|
request properties (e.g., URL, headers, decorations).
|
|
402
408
|
|
|
403
409
|
```js
|
|
410
|
+
// Deprecated
|
|
404
411
|
const fastify = require('fastify')({
|
|
405
412
|
logger: true,
|
|
406
413
|
disableRequestLogging: (request) => {
|
|
407
|
-
// Disable logging for health check endpoints
|
|
408
414
|
return request.url === '/health' || request.url === '/ready'
|
|
409
415
|
}
|
|
410
416
|
})
|
|
417
|
+
|
|
418
|
+
// Recommended: use logController instead
|
|
419
|
+
const fastify = require('fastify')({
|
|
420
|
+
logger: true,
|
|
421
|
+
logController: {
|
|
422
|
+
disableRequestLogging: (request) => {
|
|
423
|
+
return request.url === '/health' || request.url === '/ready'
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
})
|
|
411
427
|
```
|
|
412
428
|
|
|
413
429
|
The other log entries that will be disabled are:
|
|
@@ -434,6 +450,86 @@ fastify.addHook('onResponse', (req, reply, done) => {
|
|
|
434
450
|
})
|
|
435
451
|
```
|
|
436
452
|
|
|
453
|
+
### `logController`
|
|
454
|
+
<a id="factory-log-controller"></a>
|
|
455
|
+
|
|
456
|
+
+ Default: `undefined`
|
|
457
|
+
|
|
458
|
+
Accepts an instance of `LogController` (or a subclass) to customize Fastify's
|
|
459
|
+
internal log lines. Extend the `LogController` class and override only the
|
|
460
|
+
methods you want to customize; all others keep their default behavior.
|
|
461
|
+
|
|
462
|
+
The `LogController` class is exported from `fastify`:
|
|
463
|
+
|
|
464
|
+
```js
|
|
465
|
+
const { LogController } = require('fastify')
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The constructor accepts an optional options object:
|
|
469
|
+
|
|
470
|
+
| Property | Type | Default | Description |
|
|
471
|
+
|----------|------|---------|-------------|
|
|
472
|
+
| `disableRequestLogging` | `boolean \| (req) => boolean` | `false` | When `true` (or a function returning `true`), per-request log lines are suppressed. |
|
|
473
|
+
| `requestIdLogLabel` | `string` | `'reqId'` | The label used for the request identifier when logging. |
|
|
474
|
+
|
|
475
|
+
```js
|
|
476
|
+
const { LogController } = require('fastify')
|
|
477
|
+
|
|
478
|
+
class MyLogController extends LogController {
|
|
479
|
+
constructor () {
|
|
480
|
+
super({
|
|
481
|
+
requestIdLogLabel: 'traceId',
|
|
482
|
+
disableRequestLogging: (request) => {
|
|
483
|
+
return request.url === '/health'
|
|
484
|
+
}
|
|
485
|
+
})
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
incomingRequest (request, reply, metadata) {
|
|
489
|
+
// Use debug level instead of info for incoming requests
|
|
490
|
+
request.log.debug({ req: request }, 'incoming request')
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
requestCompleted (error, request, reply, metadata) {
|
|
494
|
+
// Add custom fields to the request completed log
|
|
495
|
+
if (error) {
|
|
496
|
+
reply.log.error({ res: reply, err: error, responseTime: reply.elapsedTime, customField: 'value' }, 'request errored')
|
|
497
|
+
} else {
|
|
498
|
+
reply.log.info({ res: reply, responseTime: reply.elapsedTime, customField: 'value' }, 'request completed')
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const fastify = require('fastify')({
|
|
504
|
+
logger: true,
|
|
505
|
+
logController: new MyLogController()
|
|
506
|
+
})
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
The error-related methods share a unified signature:
|
|
510
|
+
`(error, request, reply, metadata)`, where `metadata` carries any extra
|
|
511
|
+
per-method data (for example, the `statusCode` passed to `serializerError`).
|
|
512
|
+
`incomingRequest` and `routeNotFound` omit the `error` argument, since they fire
|
|
513
|
+
at lifecycle points where no error exists. `serviceUnavailable` is a further
|
|
514
|
+
exception, since no route — and therefore no `request`/`reply` — is formed.
|
|
515
|
+
|
|
516
|
+
| Method | Signature | Description |
|
|
517
|
+
|--------|-----------|-------------|
|
|
518
|
+
| `isLogDisabled` | `(request)` | Checks whether request logging is disabled for the given request. It impacts all other log methods. |
|
|
519
|
+
| `incomingRequest` | `(request, reply, metadata)` | Logs an incoming request at `info` level. |
|
|
520
|
+
| `requestCompleted` | `(error, request, reply, metadata)` | Logs the outcome of a completed request. Uses `error` level when an error is present, `info` otherwise. |
|
|
521
|
+
| `defaultErrorLog` | `(error, request, reply, metadata)` | Logs an error handled by the default error handler. Uses `error` for 5xx, `info` for 4xx. |
|
|
522
|
+
| `streamError` | `(error, request, reply, metadata)` | Logs stream-level errors after headers have been sent. |
|
|
523
|
+
| `routeNotFound` | `(request, reply, metadata)` | Logs a "route not found" message at `info` level. |
|
|
524
|
+
| `writeHeadError` | `(error, request, reply, metadata)` | Logs a warning when `writeHead` fails during error handling. |
|
|
525
|
+
| `serializerError` | `(error, request, reply, metadata)` | Logs an error when the serializer for a given status code fails. The triggering status code is available as `metadata.statusCode`. |
|
|
526
|
+
| `serviceUnavailable` | `(logger, server)` | Logs a 503 when the server is closing. Always emitted, not gated by `disableRequestLogging`. |
|
|
527
|
+
|
|
528
|
+
**Note:** When you override a method, you take full control of it — the
|
|
529
|
+
default `disableRequestLogging` check is **not** automatically applied.
|
|
530
|
+
If you need conditional logging, call `this.isLogDisabled(request)` yourself
|
|
531
|
+
or override `isLogDisabled` as well.
|
|
532
|
+
|
|
437
533
|
### `serverFactory`
|
|
438
534
|
<a id="custom-http-server"></a>
|
|
439
535
|
|
|
@@ -500,6 +596,9 @@ const fastify = require('fastify')({
|
|
|
500
596
|
### `requestIdLogLabel`
|
|
501
597
|
<a id="factory-request-id-log-label"></a>
|
|
502
598
|
|
|
599
|
+
> **Deprecated:** Use the [`logController`](#log-controller) option with
|
|
600
|
+
> `requestIdLogLabel` instead. This top-level option will be removed in `fastify@6`.
|
|
601
|
+
|
|
503
602
|
+ Default: `'reqId'`
|
|
504
603
|
|
|
505
604
|
Defines the label used for the request identifier when logging the request.
|
|
@@ -518,9 +617,9 @@ generation behavior as shown below. For generating `UUID`s you may want to check
|
|
|
518
617
|
out [hyperid](https://github.com/mcollina/hyperid).
|
|
519
618
|
|
|
520
619
|
> ℹ️ Note:
|
|
521
|
-
> `genReqId` will be
|
|
620
|
+
> `genReqId` will not be called if the header set in
|
|
522
621
|
> <code>[requestIdHeader](#requestidheader)</code> is available (defaults to
|
|
523
|
-
>
|
|
622
|
+
> `false`).
|
|
524
623
|
|
|
525
624
|
```js
|
|
526
625
|
let i = 0
|
|
@@ -560,6 +659,12 @@ For more examples, refer to the
|
|
|
560
659
|
You may access the `ip`, `ips`, `host` and `protocol` values on the
|
|
561
660
|
[`request`](./Request.md) object.
|
|
562
661
|
|
|
662
|
+
> ⚠️ Security:
|
|
663
|
+
> These values are derived from socket/forwarding metadata and must be treated
|
|
664
|
+
> as untrusted input unless your proxy chain is explicitly trusted and
|
|
665
|
+
> validated. Do not use them directly for authorization or other
|
|
666
|
+
> security-sensitive decisions without explicit validation.
|
|
667
|
+
|
|
563
668
|
```js
|
|
564
669
|
fastify.get('/', (request, reply) => {
|
|
565
670
|
console.log(request.ip)
|
|
@@ -720,7 +825,7 @@ const fastify = require('fastify')({
|
|
|
720
825
|
res.code(400)
|
|
721
826
|
return res.send("Provided header is not valid")
|
|
722
827
|
} else {
|
|
723
|
-
res.send(
|
|
828
|
+
res.send(error)
|
|
724
829
|
}
|
|
725
830
|
}
|
|
726
831
|
})
|
|
@@ -846,7 +951,7 @@ function to sanitize a route's store object to use with the `prettyPrint`
|
|
|
846
951
|
functions. This function should accept a single object and return an object.
|
|
847
952
|
|
|
848
953
|
```js
|
|
849
|
-
fastify
|
|
954
|
+
const fastify = require('fastify')({
|
|
850
955
|
routerOptions: {
|
|
851
956
|
buildPrettyMeta: route => {
|
|
852
957
|
const cleanMeta = Object.assign({}, route.store)
|
|
@@ -857,7 +962,7 @@ fastify.get('/user/:username', (request, reply) => {
|
|
|
857
962
|
})
|
|
858
963
|
|
|
859
964
|
return cleanMeta // this will show up in the pretty print output!
|
|
860
|
-
}
|
|
965
|
+
}
|
|
861
966
|
}
|
|
862
967
|
})
|
|
863
968
|
```
|
|
@@ -921,7 +1026,7 @@ const fastify = require('fastify')({
|
|
|
921
1026
|
```
|
|
922
1027
|
|
|
923
1028
|
### `defaultRoute`
|
|
924
|
-
<a id="
|
|
1029
|
+
<a id="default-route"></a>
|
|
925
1030
|
|
|
926
1031
|
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
|
|
927
1032
|
can pass a default route with the option defaultRoute.
|
|
@@ -1037,11 +1142,33 @@ const fastify = require('fastify')({
|
|
|
1037
1142
|
As with `defaultRoute`, `req` and `res` are the raw Node.js request/response
|
|
1038
1143
|
objects and do not provide Fastify's decorated helpers.
|
|
1039
1144
|
|
|
1145
|
+
### `onMaxParamLength`
|
|
1146
|
+
<a id="on-max-param-length"></a>
|
|
1147
|
+
|
|
1148
|
+
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
|
|
1149
|
+
the use case of a provide custom handler when `maxParamLength ` is exceed.
|
|
1150
|
+
|
|
1151
|
+
```js
|
|
1152
|
+
const fastify = require('fastify')({
|
|
1153
|
+
routerOptions: {
|
|
1154
|
+
maxParamLength: 10,
|
|
1155
|
+
onMaxParamLength: (path, req, res) => {
|
|
1156
|
+
res.statusCode = 414
|
|
1157
|
+
res.end(`Bad path: ${path}`)
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
})
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
As with `defaultRoute`, `req` and `res` are the raw Node.js request/response
|
|
1164
|
+
objects and do not provide Fastify's decorated helpers.
|
|
1165
|
+
|
|
1040
1166
|
### `querystringParser`
|
|
1041
1167
|
<a id="querystringparser"></a>
|
|
1042
1168
|
|
|
1043
|
-
The default query string parser that Fastify uses is
|
|
1044
|
-
`querystring` module
|
|
1169
|
+
The default query string parser that Fastify uses is a more performant fork
|
|
1170
|
+
of Node.js's core `querystring` module called
|
|
1171
|
+
[`fast-querystring`](https://github.com/anonrig/fast-querystring).
|
|
1045
1172
|
|
|
1046
1173
|
You can use this option to use a custom parser, such as
|
|
1047
1174
|
[`qs`](https://www.npmjs.com/package/qs).
|
|
@@ -1062,7 +1189,7 @@ You can also use Fastify's default parser but change some handling behavior,
|
|
|
1062
1189
|
like the example below for case insensitive keys and values:
|
|
1063
1190
|
|
|
1064
1191
|
```js
|
|
1065
|
-
const querystring = require('
|
|
1192
|
+
const querystring = require('fast-querystring')
|
|
1066
1193
|
const fastify = require('fastify')({
|
|
1067
1194
|
routerOptions: {
|
|
1068
1195
|
querystringParser: str => querystring.parse(str.toLowerCase())
|
|
@@ -2249,7 +2376,7 @@ fastify.get('/', {
|
|
|
2249
2376
|
return
|
|
2250
2377
|
}
|
|
2251
2378
|
|
|
2252
|
-
fastify.errorHandler(error, request,
|
|
2379
|
+
fastify.errorHandler(error, request, reply)
|
|
2253
2380
|
}
|
|
2254
2381
|
}, handler)
|
|
2255
2382
|
```
|
|
@@ -23,8 +23,7 @@ See also the Type Provider wrapper packages for each of the packages respectivel
|
|
|
23
23
|
|
|
24
24
|
- [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
|
|
25
25
|
- [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
|
|
26
|
-
- [
|
|
27
|
-
(3rd party)
|
|
26
|
+
- [`@fastify/type-provider-zod`](https://github.com/fastify/fastify-type-provider-zod)
|
|
28
27
|
|
|
29
28
|
### Json Schema to Ts
|
|
30
29
|
|
|
@@ -35,10 +34,10 @@ $ npm i @fastify/type-provider-json-schema-to-ts
|
|
|
35
34
|
```
|
|
36
35
|
|
|
37
36
|
```typescript
|
|
38
|
-
import
|
|
37
|
+
import Fastify from 'fastify'
|
|
39
38
|
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
|
|
40
39
|
|
|
41
|
-
const server =
|
|
40
|
+
const server = Fastify().withTypeProvider<JsonSchemaToTsProvider>()
|
|
42
41
|
|
|
43
42
|
server.get('/route', {
|
|
44
43
|
schema: {
|
|
@@ -58,6 +57,26 @@ server.get('/route', {
|
|
|
58
57
|
})
|
|
59
58
|
```
|
|
60
59
|
|
|
60
|
+
When using raw JSON Schema objects with `JsonSchemaToTsProvider`, TypeScript
|
|
61
|
+
must be able to see the exact literal values in the schema. Inline schemas, like
|
|
62
|
+
the example above, are inferred from the route call. If the schema is moved into
|
|
63
|
+
a separate variable, use `as const`:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const querystringSchema = {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {
|
|
69
|
+
foo: { type: 'number' },
|
|
70
|
+
bar: { type: 'string' },
|
|
71
|
+
},
|
|
72
|
+
required: ['foo', 'bar']
|
|
73
|
+
} as const
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Without `as const`, TypeScript may widen schema values such as `type: 'object'`
|
|
77
|
+
to `type: string`, which prevents `json-schema-to-ts` from inferring the route
|
|
78
|
+
types. This assertion has no effect on the schema used by Fastify at runtime.
|
|
79
|
+
|
|
61
80
|
### TypeBox
|
|
62
81
|
|
|
63
82
|
The following sets up a TypeBox Type Provider:
|
|
@@ -67,11 +86,11 @@ $ npm i typebox @fastify/type-provider-typebox
|
|
|
67
86
|
```
|
|
68
87
|
|
|
69
88
|
```typescript
|
|
70
|
-
import
|
|
89
|
+
import Fastify from 'fastify'
|
|
71
90
|
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
72
91
|
import { Type } from 'typebox'
|
|
73
92
|
|
|
74
|
-
const server =
|
|
93
|
+
const server = Fastify().withTypeProvider<TypeBoxTypeProvider>()
|
|
75
94
|
|
|
76
95
|
server.get('/route', {
|
|
77
96
|
schema: {
|
|
@@ -88,14 +107,39 @@ server.get('/route', {
|
|
|
88
107
|
```
|
|
89
108
|
|
|
90
109
|
See the [TypeBox
|
|
91
|
-
documentation](https://sinclairzx81.github.io/typebox
|
|
110
|
+
documentation](https://sinclairzx81.github.io/typebox/)
|
|
92
111
|
for setting-up AJV to work with TypeBox.
|
|
93
112
|
|
|
94
113
|
### Zod
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
The following sets up a Zod Type Provider:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
$ npm i zod @fastify/type-provider-zod
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import fastify from 'fastify'
|
|
123
|
+
import { ZodTypeProvider, serializerCompiler, validatorCompiler } from '@fastify/type-provider-zod'
|
|
124
|
+
import { z } from 'zod/v4'
|
|
125
|
+
|
|
126
|
+
const server = fastify()
|
|
127
|
+
server.setValidatorCompiler(validatorCompiler)
|
|
128
|
+
server.setSerializerCompiler(serializerCompiler)
|
|
98
129
|
|
|
130
|
+
server.withTypeProvider<ZodTypeProvider>().get('/route', {
|
|
131
|
+
schema: {
|
|
132
|
+
querystring: z.object({
|
|
133
|
+
foo: z.number(),
|
|
134
|
+
bar: z.string()
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}, (request, reply) => {
|
|
138
|
+
|
|
139
|
+
// type Query = { foo: number, bar: string }
|
|
140
|
+
const { foo, bar } = request.query // type safe!
|
|
141
|
+
})
|
|
142
|
+
```
|
|
99
143
|
|
|
100
144
|
### Scoped Type-Provider
|
|
101
145
|
|
|
@@ -658,8 +658,8 @@ unfortunate limitation of using TypeScript and is unavoidable as of right now.
|
|
|
658
658
|
|
|
659
659
|
However, there are a couple of suggestions to help improve this experience:
|
|
660
660
|
- Make sure the `no-unused-vars` rule is enabled in
|
|
661
|
-
[ESLint](https://eslint.org/docs/rules/no-unused-vars) and any
|
|
662
|
-
are actually being loaded.
|
|
661
|
+
[ESLint](https://eslint.org/docs/latest/rules/no-unused-vars) and any
|
|
662
|
+
imported plugin are actually being loaded.
|
|
663
663
|
- Use a module such as [depcheck](https://www.npmjs.com/package/depcheck) or
|
|
664
664
|
[npm-check](https://www.npmjs.com/package/npm-check) to verify plugin
|
|
665
665
|
dependencies are being used somewhere in your project.
|
|
@@ -828,7 +828,7 @@ fastify.addHook('preHandler', async (req, reply) => {
|
|
|
828
828
|
## Code Completion In Vanilla JavaScript
|
|
829
829
|
|
|
830
830
|
Vanilla JavaScript can use the published types to provide code completion (e.g.
|
|
831
|
-
[Intellisense](https://code.visualstudio.com/docs/
|
|
831
|
+
[Intellisense](https://code.visualstudio.com/docs/editing/intellisense)) by
|
|
832
832
|
following the [TypeScript JSDoc
|
|
833
833
|
Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html).
|
|
834
834
|
|
|
@@ -300,6 +300,12 @@ Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html) values to
|
|
|
300
300
|
the types specified in the schema `type` keywords, both to pass validation and
|
|
301
301
|
to use the correctly typed data afterwards.
|
|
302
302
|
|
|
303
|
+
> ⚠ Important:
|
|
304
|
+
> Fastify uses a custom [AJV configuration][1] such as `coerceTypes: 'array'`.
|
|
305
|
+
> Evaluate its behavior and verify if it meets the project requirements.
|
|
306
|
+
|
|
307
|
+
[1]: https://github.com/fastify/ajv-compiler?tab=readme-ov-file#ajv-configuration
|
|
308
|
+
|
|
303
309
|
The Ajv default configuration in Fastify supports coercing array parameters in
|
|
304
310
|
`querystring`. Example:
|
|
305
311
|
|
|
@@ -583,6 +589,11 @@ fastify.post('/the/url', {
|
|
|
583
589
|
}, handler)
|
|
584
590
|
```
|
|
585
591
|
|
|
592
|
+
Fastify supports different JSON Schema validators via
|
|
593
|
+
`setValidatorCompiler`. Community plugins that integrate alternative JSON
|
|
594
|
+
Schema validators are listed on the
|
|
595
|
+
[Ecosystem](https://fastify.dev/docs/latest/Guides/Ecosystem/) page.
|
|
596
|
+
|
|
586
597
|
##### Custom Validator Best Practices
|
|
587
598
|
|
|
588
599
|
When implementing custom validators, follow these patterns to ensure compatibility
|
|
@@ -920,8 +931,10 @@ For custom error responses in the schema, see
|
|
|
920
931
|
[example](https://github.com/fastify/example/blob/HEAD/validation-messages/custom-errors-messages.js)
|
|
921
932
|
usage.
|
|
922
933
|
|
|
923
|
-
>
|
|
924
|
-
>
|
|
934
|
+
> Fastify v5 uses AJV v8 and requires a compatible `ajv-errors` version.
|
|
935
|
+
> Fastify v3 requires `ajv-errors@1.0.1`, which supports AJV v6.
|
|
936
|
+
> See the [AJV compiler versions table](https://github.com/fastify/ajv-compiler/#versions)
|
|
937
|
+
> for the AJV version used by each Fastify release.
|
|
925
938
|
|
|
926
939
|
Below is an example showing how to add **custom error messages for each
|
|
927
940
|
property** of a schema by supplying custom AJV options. Inline comments in the
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
- [Warnings In Fastify](#warnings-in-fastify)
|
|
7
7
|
- [Fastify Warning Codes](#fastify-warning-codes)
|
|
8
8
|
- [FSTWRN001](#FSTWRN001)
|
|
9
|
-
- [
|
|
9
|
+
- [FSTWRN003](#FSTWRN003)
|
|
10
|
+
- [FSTWRN004](#FSTWRN004)
|
|
10
11
|
- [Fastify Deprecation Codes](#fastify-deprecation-codes)
|
|
11
12
|
- [FSTDEP022](#FSTDEP022)
|
|
13
|
+
- [FSTDEP023](#FSTDEP023)
|
|
14
|
+
- [FSTDEP024](#FSTDEP024)
|
|
12
15
|
|
|
13
16
|
## Warnings
|
|
14
17
|
|
|
15
18
|
### Warnings In Fastify
|
|
16
19
|
|
|
17
|
-
Fastify uses Node.js
|
|
20
|
+
Fastify uses the Node.js [warning event](https://nodejs.org/api/process.html#event-warning)
|
|
18
21
|
API to notify users of deprecated features and coding mistakes. Fastify's
|
|
19
22
|
warnings are recognizable by the `FSTWRN` and `FSTDEP` prefixes. When
|
|
20
23
|
encountering such a warning, it is highly recommended to determine the cause
|
|
@@ -22,7 +25,7 @@ using the [`--trace-warnings`](https://nodejs.org/api/cli.html#trace-warnings)
|
|
|
22
25
|
and [`--trace-deprecation`](https://nodejs.org/api/cli.html#trace-deprecation)
|
|
23
26
|
flags. These produce stack traces pointing to where the issue occurs in the
|
|
24
27
|
application's code. Issues opened about warnings without this information will
|
|
25
|
-
be closed
|
|
28
|
+
be closed.
|
|
26
29
|
|
|
27
30
|
Warnings can also be disabled, though it is not recommended. If necessary, use
|
|
28
31
|
one of the following methods:
|
|
@@ -33,15 +36,15 @@ one of the following methods:
|
|
|
33
36
|
|
|
34
37
|
For more information on disabling warnings, see [Node's documentation](https://nodejs.org/api/cli.html).
|
|
35
38
|
|
|
36
|
-
Disabling warnings
|
|
37
|
-
experienced users should consider disabling warnings.
|
|
39
|
+
Disabling warnings is not recommended and may cause unexpected behavior.
|
|
38
40
|
|
|
39
41
|
### Fastify Warning Codes
|
|
40
42
|
|
|
41
43
|
| Code | Description | How to solve | Discussion |
|
|
42
44
|
| ---- | ----------- | ------------ | ---------- |
|
|
43
45
|
| <a id="FSTWRN001">FSTWRN001</a> | The specified schema for a route is missing. This may indicate the schema is not well specified. | Check the schema for the route. | [#4647](https://github.com/fastify/fastify/pull/4647) |
|
|
44
|
-
| <a id="
|
|
46
|
+
| <a id="FSTWRN003">FSTWRN003</a> | The `%s` plugin mixes async and callback styles, which may lead to unhandled rejections. | Do not mix async and callback style. | [#6011](https://github.com/fastify/fastify/pull/6011) |
|
|
47
|
+
| <a id="FSTWRN004">FSTWRN004</a> | An `errorHandler` is being overridden in the same scope, which can lead to subtle bugs. | Avoid calling `setErrorHandler` more than once in the same scope. For more information, see [Server documentation](https://fastify.dev/docs/latest/Reference/Server/#allowerrorhandleroverride). | [#6104](https://github.com/fastify/fastify/pull/6104) |
|
|
45
48
|
|
|
46
49
|
|
|
47
50
|
### Fastify Deprecation Codes
|
|
@@ -56,3 +59,5 @@ Deprecation codes are supported by the Node.js CLI options:
|
|
|
56
59
|
| Code | Description | How to solve | Discussion |
|
|
57
60
|
| ---- | ----------- | ------------ | ---------- |
|
|
58
61
|
| <a id="FSTDEP022">FSTDEP022</a> | You are trying to access the deprecated router options on top option properties. | Use `options.routerOptions`. | [#5985](https://github.com/fastify/fastify/pull/5985)
|
|
62
|
+
| <a id="FSTDEP023">FSTDEP023</a> | `disableRequestLogging` top-level option is deprecated. | Pass a `LogController` instance via the `logController` option with `disableRequestLogging` in its constructor instead. |
|
|
63
|
+
| <a id="FSTDEP024">FSTDEP024</a> | `requestIdLogLabel` top-level option is deprecated. | Pass a `LogController` instance via the `logController` option with `requestIdLogLabel` in its constructor instead. |
|
package/eslint.config.js
CHANGED
|
@@ -6,8 +6,7 @@ module.exports = [
|
|
|
6
6
|
ignores: [
|
|
7
7
|
'lib/config-validator.js',
|
|
8
8
|
'lib/error-serializer.js',
|
|
9
|
-
'test/same-shape.test.js'
|
|
10
|
-
'test/types/import.js'
|
|
9
|
+
'test/same-shape.test.js'
|
|
11
10
|
],
|
|
12
11
|
ts: true
|
|
13
12
|
}),
|
|
@@ -31,5 +30,11 @@ module.exports = [
|
|
|
31
30
|
rules: {
|
|
32
31
|
'max-len': 'off'
|
|
33
32
|
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
files: ['test/types/**/*'],
|
|
36
|
+
rules: {
|
|
37
|
+
'@typescript-eslint/no-unused-vars': 'off'
|
|
38
|
+
}
|
|
34
39
|
}
|
|
35
40
|
]
|