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.
Files changed (126) hide show
  1. package/PROJECT_CHARTER.md +1 -1
  2. package/README.md +7 -10
  3. package/SECURITY.md +1 -1
  4. package/SPONSORS.md +6 -4
  5. package/build/build-validation.js +2 -2
  6. package/docs/Guides/Database.md +0 -28
  7. package/docs/Guides/Delay-Accepting-Requests.md +1 -1
  8. package/docs/Guides/Ecosystem.md +23 -9
  9. package/docs/Guides/Getting-Started.md +2 -2
  10. package/docs/Guides/Migration-Guide-V4.md +2 -2
  11. package/docs/Guides/Migration-Guide-V5.md +1 -1
  12. package/docs/Guides/Plugins-Guide.md +1 -1
  13. package/docs/Guides/Prototype-Poisoning.md +3 -3
  14. package/docs/Guides/Serverless.md +8 -15
  15. package/docs/Guides/Style-Guide.md +1 -1
  16. package/docs/Guides/Write-Plugin.md +1 -1
  17. package/docs/Reference/Encapsulation.md +27 -26
  18. package/docs/Reference/Errors.md +12 -4
  19. package/docs/Reference/HTTP2.md +10 -10
  20. package/docs/Reference/Hooks.md +5 -5
  21. package/docs/Reference/Index.md +14 -16
  22. package/docs/Reference/LTS.md +12 -13
  23. package/docs/Reference/Lifecycle.md +9 -8
  24. package/docs/Reference/Logging.md +47 -39
  25. package/docs/Reference/Middleware.md +21 -25
  26. package/docs/Reference/Principles.md +2 -2
  27. package/docs/Reference/Reply.md +6 -1
  28. package/docs/Reference/Request.md +29 -18
  29. package/docs/Reference/Routes.md +5 -2
  30. package/docs/Reference/Server.md +138 -11
  31. package/docs/Reference/Type-Providers.md +53 -9
  32. package/docs/Reference/TypeScript.md +3 -3
  33. package/docs/Reference/Validation-and-Serialization.md +15 -2
  34. package/docs/Reference/Warnings.md +11 -6
  35. package/eslint.config.js +7 -2
  36. package/fastify.d.ts +13 -3
  37. package/fastify.js +60 -31
  38. package/lib/content-type-parser.js +2 -0
  39. package/lib/content-type.js +34 -1
  40. package/lib/context.js +0 -3
  41. package/lib/decorate.js +11 -3
  42. package/lib/error-handler.js +10 -28
  43. package/lib/error-serializer.js +59 -59
  44. package/lib/errors.js +23 -1
  45. package/lib/four-oh-four.js +22 -19
  46. package/lib/handle-request.js +12 -5
  47. package/lib/log-controller.js +169 -0
  48. package/lib/logger-factory.js +25 -4
  49. package/lib/plugin-override.js +2 -1
  50. package/lib/plugin-utils.js +5 -5
  51. package/lib/reply.js +96 -50
  52. package/lib/req-id-gen-factory.js +4 -1
  53. package/lib/request.js +16 -6
  54. package/lib/route.js +47 -41
  55. package/lib/schema-controller.js +1 -1
  56. package/lib/schemas.js +37 -30
  57. package/lib/symbols.js +4 -2
  58. package/lib/validation.js +10 -13
  59. package/lib/warnings.js +22 -4
  60. package/package.json +15 -17
  61. package/scripts/validate-ecosystem-links.js +1 -0
  62. package/test/bundler/esbuild/package.json +1 -1
  63. package/test/close-pipelining.test.js +1 -2
  64. package/test/content-type.test.js +20 -0
  65. package/test/custom-http-server.test.js +38 -0
  66. package/test/decorator-instance-properties.test.js +63 -0
  67. package/test/diagnostics-channel/async-error-handler.test.js +74 -0
  68. package/test/genReqId.test.js +24 -0
  69. package/test/hooks.test.js +94 -0
  70. package/test/http-methods/get.test.js +1 -1
  71. package/test/http2/plain.test.js +135 -0
  72. package/test/http2/secure-with-fallback.test.js +1 -1
  73. package/test/https/https.test.js +1 -2
  74. package/test/internals/errors.test.js +31 -1
  75. package/test/internals/logger.test.js +322 -0
  76. package/test/internals/plugin.test.js +3 -1
  77. package/test/internals/reply.test.js +35 -4
  78. package/test/internals/request.test.js +37 -10
  79. package/test/internals/schema-controller-perf.test.js +33 -0
  80. package/test/logger/logging.test.js +57 -1
  81. package/test/logger/options.test.js +38 -1
  82. package/test/reply-error.test.js +1 -1
  83. package/test/reply-trailers.test.js +70 -0
  84. package/test/request-media-type.test.js +105 -0
  85. package/test/route-prefix.test.js +34 -0
  86. package/test/router-options.test.js +222 -11
  87. package/test/schema-serialization.test.js +108 -0
  88. package/test/schema-validation.test.js +24 -0
  89. package/test/scripts/validate-ecosystem-links.test.js +40 -57
  90. package/test/stream.4.test.js +2 -2
  91. package/test/throw.test.js +14 -0
  92. package/test/trust-proxy.test.js +70 -30
  93. package/test/types/content-type-parser.tst.ts +70 -0
  94. package/test/types/{decorate-request-reply.test-d.ts → decorate-request-reply.tst.ts} +4 -4
  95. package/test/types/{dummy-plugin.ts → dummy-plugin.mts} +1 -1
  96. package/test/types/errors.tst.ts +91 -0
  97. package/test/types/fastify.tst.ts +351 -0
  98. package/test/types/hooks.tst.ts +578 -0
  99. package/test/types/instance.tst.ts +597 -0
  100. package/test/types/{logger.test-d.ts → logger.tst.ts} +61 -62
  101. package/test/types/plugin.tst.ts +96 -0
  102. package/test/types/register.tst.ts +245 -0
  103. package/test/types/reply.tst.ts +297 -0
  104. package/test/types/request.tst.ts +199 -0
  105. package/test/types/route.tst.ts +576 -0
  106. package/test/types/{schema.test-d.ts → schema.tst.ts} +22 -22
  107. package/test/types/{serverFactory.test-d.ts → serverFactory.tst.ts} +4 -4
  108. package/test/types/tsconfig.json +9 -0
  109. package/test/types/{type-provider.test-d.ts → type-provider.tst.ts} +256 -250
  110. package/test/types/using.tst.ts +14 -0
  111. package/types/errors.d.ts +4 -0
  112. package/types/instance.d.ts +2 -0
  113. package/types/logger.d.ts +22 -0
  114. package/types/request.d.ts +23 -2
  115. package/test/types/content-type-parser.test-d.ts +0 -72
  116. package/test/types/errors.test-d.ts +0 -90
  117. package/test/types/fastify.test-d.ts +0 -352
  118. package/test/types/hooks.test-d.ts +0 -550
  119. package/test/types/import.ts +0 -2
  120. package/test/types/instance.test-d.ts +0 -588
  121. package/test/types/plugin.test-d.ts +0 -97
  122. package/test/types/register.test-d.ts +0 -237
  123. package/test/types/reply.test-d.ts +0 -254
  124. package/test/types/request.test-d.ts +0 -188
  125. package/test/types/route.test-d.ts +0 -553
  126. 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. Zero overhead in production
7
- 2. Good developer experience
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
@@ -219,7 +219,7 @@ reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
219
219
  ```
220
220
 
221
221
  ### .removeHeader(key)
222
- <a id="getHeader"></a>
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
- - `ips` - An array of the IP addresses, ordered from closest to furthest, in the
21
- `X-Forwarded-For` header of the incoming request (only when the
22
- [`trustProxy`](./Server.md#factory-trust-proxy) option is enabled).
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
- header when the [`trustProxy`](./Server.md#factory-trust-proxy) option is
25
- enabled). For HTTP/2 compatibility, it returns `:authority` if no host header
26
- exists. The host header may return an empty string if `requireHostHeader` is
27
- `false`, not provided with HTTP/1.0, or removed by schema validation.
28
- Security: this value comes from client-controlled headers; only trust it
29
- when you control proxy behavior and have validated or allow-listed hosts.
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.method)
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.logLevel)
142
+ console.log(request.routeOptions.config)
132
143
  request.log.info('some info')
133
144
  })
134
145
  ```
@@ -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({ { schema, method, url, httpStatus, contentType } })`:
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.
@@ -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 not called if the header set in
620
+ > `genReqId` will not be called if the header set in
522
621
  > <code>[requestIdHeader](#requestidheader)</code> is available (defaults to
523
- > 'request-id').
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(err)
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.get('/user/:username', (request, reply) => {
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="on-bad-url"></a>
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 the Node.js's core
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('node:querystring')
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, response)
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
- - [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
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 fastify from 'fastify'
37
+ import Fastify from 'fastify'
39
38
  import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
40
39
 
41
- const server = fastify().withTypeProvider<JsonSchemaToTsProvider>()
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 fastify from 'fastify'
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 = fastify().withTypeProvider<TypeBoxTypeProvider>()
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/#/docs/overview/2_setup)
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
- See [official documentation](https://github.com/turkerdev/fastify-type-provider-zod)
97
- for Zod Type Provider instructions.
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 imported plugin
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/editor/intellisense)) by
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
- > Install version 1.0.1 of `ajv-errors`, as later versions are not compatible
924
- > with AJV v6 (the version shipped by Fastify v3).
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
- - [FSTWRN002](#FSTWRN002)
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's [warning event](https://nodejs.org/api/process.html#event-warning)
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 due to lack of details.
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 may cause issues when upgrading Fastify versions. Only
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="FSTWRN002">FSTWRN002</a> | The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`. | Do not mix async and callback style. | [#5139](https://github.com/fastify/fastify/pull/5139) |
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
  ]