fastify 4.25.2 → 4.26.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 (52) hide show
  1. package/.vscode/settings.json +22 -0
  2. package/EXPENSE_POLICY.md +105 -0
  3. package/GOVERNANCE.md +2 -103
  4. package/LICENSE +1 -1
  5. package/README.md +13 -9
  6. package/SECURITY.md +2 -157
  7. package/SPONSORS.md +20 -0
  8. package/build/build-validation.js +3 -1
  9. package/docs/Guides/Ecosystem.md +27 -9
  10. package/docs/Guides/Getting-Started.md +16 -3
  11. package/docs/Guides/Style-Guide.md +7 -7
  12. package/docs/Reference/Decorators.md +1 -1
  13. package/docs/Reference/Errors.md +63 -1
  14. package/docs/Reference/Hooks.md +1 -1
  15. package/docs/Reference/Logging.md +3 -3
  16. package/docs/Reference/Reply.md +70 -1
  17. package/docs/Reference/Server.md +90 -0
  18. package/docs/Reference/Warnings.md +2 -0
  19. package/fastify.d.ts +3 -2
  20. package/fastify.js +25 -7
  21. package/lib/configValidator.js +62 -33
  22. package/lib/contentTypeParser.js +9 -2
  23. package/lib/error-handler.js +1 -1
  24. package/lib/error-serializer.js +2 -0
  25. package/lib/errors.js +4 -0
  26. package/lib/fourOhFour.js +4 -3
  27. package/lib/hooks.js +1 -5
  28. package/lib/reply.js +68 -10
  29. package/lib/reqIdGenFactory.js +5 -0
  30. package/lib/route.js +22 -6
  31. package/lib/schema-controller.js +37 -4
  32. package/lib/symbols.js +1 -0
  33. package/lib/warnings.js +6 -0
  34. package/package.json +17 -5
  35. package/test/async_hooks.test.js +69 -0
  36. package/test/findRoute.test.js +135 -0
  37. package/test/genReqId.test.js +392 -0
  38. package/test/hooks.on-listen.test.js +66 -14
  39. package/test/internals/errors.test.js +17 -7
  40. package/test/internals/initialConfig.test.js +7 -3
  41. package/test/internals/reply.test.js +80 -5
  42. package/test/schema-serialization.test.js +41 -0
  43. package/test/schema-validation.test.js +115 -6
  44. package/test/serialize-response.test.js +187 -0
  45. package/test/types/instance.test-d.ts +14 -1
  46. package/test/types/reply.test-d.ts +4 -2
  47. package/test/types/route.test-d.ts +15 -1
  48. package/test/useSemicolonDelimiter.test.js +113 -0
  49. package/test/web-api.test.js +208 -0
  50. package/types/instance.d.ts +23 -10
  51. package/types/reply.d.ts +4 -0
  52. package/test/types/import.js +0 -2
@@ -55,6 +55,14 @@ fastify.listen({ port: 3000 }, function (err, address) {
55
55
  })
56
56
  ```
57
57
 
58
+ > If you are using ECMAScript Modules (ESM) in your project, be sure to
59
+ > include "type": "module" in your package.json.
60
+ >```js
61
+ >{
62
+ > "type": "module"
63
+ >}
64
+ >```
65
+
58
66
  Do you prefer to use `async/await`? Fastify supports it out-of-the-box.
59
67
 
60
68
  ```js
@@ -172,13 +180,14 @@ fastify.listen({ port: 3000 }, function (err, address) {
172
180
  })
173
181
  ```
174
182
 
183
+
175
184
  ```js
176
185
  // our-first-route.js
177
186
 
178
187
  /**
179
188
  * Encapsulates the routes
180
189
  * @param {FastifyInstance} fastify Encapsulated Fastify Instance
181
- * @param {Object} options plugin options, refer to https://www.fastify.dev/docs/latest/Reference/Plugins/#plugin-options
190
+ * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options
182
191
  */
183
192
  async function routes (fastify, options) {
184
193
  fastify.get('/', async (request, reply) => {
@@ -186,6 +195,10 @@ async function routes (fastify, options) {
186
195
  })
187
196
  }
188
197
 
198
+ //ESM
199
+ export default routes;
200
+
201
+ // CommonJs
189
202
  module.exports = routes
190
203
  ```
191
204
  In this example, we used the `register` API, which is the core of the Fastify
@@ -293,7 +306,7 @@ const fastifyPlugin = require('fastify-plugin')
293
306
  /**
294
307
  * Connects to a MongoDB database
295
308
  * @param {FastifyInstance} fastify Encapsulated Fastify Instance
296
- * @param {Object} options plugin options, refer to https://www.fastify.dev/docs/latest/Reference/Plugins/#plugin-options
309
+ * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options
297
310
  */
298
311
  async function dbConnector (fastify, options) {
299
312
  fastify.register(require('@fastify/mongodb'), {
@@ -312,7 +325,7 @@ module.exports = fastifyPlugin(dbConnector)
312
325
  /**
313
326
  * A plugin that provide encapsulated routes
314
327
  * @param {FastifyInstance} fastify encapsulated fastify instance
315
- * @param {Object} options plugin options, refer to https://www.fastify.dev/docs/latest/Reference/Plugins/#plugin-options
328
+ * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options
316
329
  */
317
330
  async function routes (fastify, options) {
318
331
  const collection = fastify.mongo.db.collection('test_collection')
@@ -13,7 +13,7 @@ This guide is for anyone who loves to build with Fastify or wants to contribute
13
13
  to our documentation. You do not need to be an expert in writing technical
14
14
  documentation. This guide is here to help you.
15
15
 
16
- Visit the [contribute](https://www.fastify.dev/contribute) page on our website or
16
+ Visit the [contribute](https://fastify.dev/contribute) page on our website or
17
17
  read the
18
18
  [CONTRIBUTING.md](https://github.com/fastify/fastify/blob/main/CONTRIBUTING.md)
19
19
  file on GitHub to join our Open Source folks.
@@ -70,12 +70,12 @@ markdown.
70
70
  **Example**
71
71
 
72
72
  ```
73
- To learn more about hooks, see [Fastify hooks](https://www.fastify.dev/docs/latest/Reference/Hooks/).
73
+ To learn more about hooks, see [Fastify hooks](https://fastify.dev/docs/latest/Reference/Hooks/).
74
74
  ```
75
75
 
76
76
  Result:
77
77
  >To learn more about hooks, see [Fastify
78
- >hooks](https://www.fastify.dev/docs/latest/Reference/Hooks/).
78
+ >hooks](https://fastify.dev/docs/latest/Reference/Hooks/).
79
79
 
80
80
 
81
81
 
@@ -224,18 +224,18 @@ hyperlink should look:
224
224
  <!-- More like this -->
225
225
 
226
226
  // Add clear & brief description
227
- [Fastify Plugins] (https://www.fastify.dev/docs/latest/Plugins/)
227
+ [Fastify Plugins] (https://fastify.dev/docs/latest/Plugins/)
228
228
 
229
229
  <!--Less like this -->
230
230
 
231
231
  // incomplete description
232
- [Fastify] (https://www.fastify.dev/docs/latest/Plugins/)
232
+ [Fastify] (https://fastify.dev/docs/latest/Plugins/)
233
233
 
234
234
  // Adding title in link brackets
235
- [](https://www.fastify.dev/docs/latest/Plugins/ "fastify plugin")
235
+ [](https://fastify.dev/docs/latest/Plugins/ "fastify plugin")
236
236
 
237
237
  // Empty title
238
- [](https://www.fastify.dev/docs/latest/Plugins/)
238
+ [](https://fastify.dev/docs/latest/Plugins/)
239
239
 
240
240
  // Adding links localhost URLs instead of using code strings (``)
241
241
  [http://localhost:3000/](http://localhost:3000/)
@@ -101,7 +101,7 @@ console.log(fastify.conf.db)
101
101
  ```
102
102
 
103
103
  The decorated [Fastify server](./Server.md) is bound to `this` in
104
- route [route](./Routes.md) handlers:
104
+ [route](./Routes.md) handlers:
105
105
 
106
106
  ```js
107
107
  fastify.decorate('db', new DbConnection())
@@ -45,6 +45,7 @@
45
45
  - [FST_ERR_LOG_INVALID_DESTINATION](#fst_err_log_invalid_destination)
46
46
  - [FST_ERR_LOG_INVALID_LOGGER](#fst_err_log_invalid_logger)
47
47
  - [FST_ERR_REP_INVALID_PAYLOAD_TYPE](#fst_err_rep_invalid_payload_type)
48
+ - [FST_ERR_REP_RESPONSE_BODY_CONSUMED](#fst_err_rep_response_body_consumed)
48
49
  - [FST_ERR_REP_ALREADY_SENT](#fst_err_rep_already_sent)
49
50
  - [FST_ERR_REP_SENT_VALUE](#fst_err_rep_sent_value)
50
51
  - [FST_ERR_SEND_INSIDE_ONERR](#fst_err_send_inside_onerr)
@@ -169,6 +170,65 @@ Some things to consider in your custom error handler:
169
170
  internally monitors the error invocation to avoid infinite loops for errors
170
171
  thrown in the reply phases of the lifecycle. (those after the route handler)
171
172
 
173
+ When utilizing Fastify's custom error handling through [`setErrorHandler`](./Server.md#seterrorhandler),
174
+ you should be aware of how errors are propagated between custom and default
175
+ error handlers.
176
+
177
+ If a plugin's error handler re-throws an error, and the error is not an
178
+ instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
179
+ (as seen in the `/bad` route in the following example), it will not propagate
180
+ to the parent context error handler. Instead, it will be caught by the default
181
+ error handler.
182
+
183
+ To ensure consistent error handling, it is recommended to throw instances of
184
+ `Error`. For instance, in the following example, replacing `throw 'foo'` with
185
+ `throw new Error('foo')` in the `/bad` route ensures that errors propagate through
186
+ the custom error handling chain as intended. This practice helps avoid potential
187
+ pitfalls when working with custom error handling in Fastify.
188
+
189
+ For example:
190
+ ```js
191
+ const Fastify = require('fastify')
192
+
193
+ // Instantiate the framework
194
+ const fastify = Fastify({
195
+ logger: true
196
+ })
197
+
198
+ // Register parent error handler
199
+ fastify.setErrorHandler((error, request, reply) => {
200
+ reply.status(500).send({ ok: false })
201
+ })
202
+
203
+ fastify.register((app, options, next) => {
204
+ // Register child error handler
205
+ fastify.setErrorHandler((error, request, reply) => {
206
+ throw error
207
+ })
208
+
209
+ fastify.get('/bad', async () => {
210
+ // Throws a non-Error type, 'bar'
211
+ throw 'foo'
212
+ })
213
+
214
+ fastify.get('/good', async () => {
215
+ // Throws an Error instance, 'bar'
216
+ throw new Error('bar')
217
+ })
218
+
219
+ next()
220
+ })
221
+
222
+ // Run the server
223
+ fastify.listen({ port: 3000 }, function (err, address) {
224
+ if (err) {
225
+ fastify.log.error(err)
226
+ process.exit(1)
227
+ }
228
+ // Server is listening at ${address}
229
+ })
230
+ ```
231
+
172
232
  ### Fastify Error Codes
173
233
  <a id="fastify-error-codes"></a>
174
234
 
@@ -183,7 +243,7 @@ const errorCodes = require('fastify').errorCodes
183
243
 
184
244
  For example:
185
245
  ```js
186
- const Fastify = require('./fastify')
246
+ const Fastify = require('fastify')
187
247
 
188
248
  // Instantiate the framework
189
249
  const fastify = Fastify({
@@ -253,6 +313,8 @@ Below is a table with all the error codes that Fastify uses.
253
313
  | <a id="fst_err_log_invalid_destination">FST_ERR_LOG_INVALID_DESTINATION</a> | The logger does not accept the specified destination. | Use a `'stream'` or a `'file'` as the destination. | [#1168](https://github.com/fastify/fastify/pull/1168) |
254
314
  | <a id="fst_err_log_invalid_logger">FST_ERR_LOG_INVALID_LOGGER</a> | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
255
315
  | <a id="fst_err_rep_invalid_payload_type">FST_ERR_REP_INVALID_PAYLOAD_TYPE</a> | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |
316
+ | <a id="fst_err_rep_response_body_consumed">FST_ERR_REP_RESPONSE_BODY_CONSUMED</a> | Using `Response` as reply payload
317
+ but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |
256
318
  | <a id="fst_err_rep_already_sent">FST_ERR_REP_ALREADY_SENT</a> | A response was already sent. | - | [#1336](https://github.com/fastify/fastify/pull/1336) |
257
319
  | <a id="fst_err_rep_sent_value">FST_ERR_REP_SENT_VALUE</a> | The only possible value for `reply.sent` is `true`. | - | [#1336](https://github.com/fastify/fastify/pull/1336) |
258
320
  | <a id="fst_err_send_inside_onerr">FST_ERR_SEND_INSIDE_ONERR</a> | You cannot use `send` inside the `onError` hook. | - | [#1348](https://github.com/fastify/fastify/pull/1348) |
@@ -232,7 +232,7 @@ fastify.addHook('onSend', (request, reply, payload, done) => {
232
232
  > `null`.
233
233
 
234
234
  Note: If you change the payload, you may only change it to a `string`, a
235
- `Buffer`, a `stream`, or `null`.
235
+ `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
236
236
 
237
237
 
238
238
  ### onResponse
@@ -61,9 +61,9 @@ the Fastify instance:
61
61
  fastify.log.info('Something important happened!');
62
62
  ```
63
63
 
64
- If you want to pass some options to the logger, just pass them to Fastify. You
65
- can find all available options in the [Pino
66
- documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#pinooptions-stream).
64
+ If you want to pass some options to the logger, just pass them to Fastify.
65
+ You can find all available options in the
66
+ [Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options).
67
67
  If you want to specify a file destination, use:
68
68
 
69
69
  ```js
@@ -4,6 +4,7 @@
4
4
  - [Reply](#reply)
5
5
  - [Introduction](#introduction)
6
6
  - [.code(statusCode)](#codestatuscode)
7
+ - [.elapsedTime](#elapsedtime)
7
8
  - [.statusCode](#statuscode)
8
9
  - [.server](#server)
9
10
  - [.header(key, value)](#headerkey-value)
@@ -32,6 +33,8 @@
32
33
  - [Strings](#strings)
33
34
  - [Streams](#streams)
34
35
  - [Buffers](#buffers)
36
+ - [ReadableStream](#send-readablestream)
37
+ - [Response](#send-response)
35
38
  - [Errors](#errors)
36
39
  - [Type of the final payload](#type-of-the-final-payload)
37
40
  - [Async-Await and Promises](#async-await-and-promises)
@@ -46,6 +49,8 @@ object that exposes the following functions and properties:
46
49
  - `.code(statusCode)` - Sets the status code.
47
50
  - `.status(statusCode)` - An alias for `.code(statusCode)`.
48
51
  - `.statusCode` - Read and set the HTTP status code.
52
+ - `.elapsedTime` - Returns the amount of time passed
53
+ since the request was received by Fastify.
49
54
  - `.server` - A reference to the fastify instance object.
50
55
  - `.header(name, value)` - Sets a response header.
51
56
  - `.headers(object)` - Sets all the keys of the object as response headers.
@@ -85,6 +90,8 @@ object that exposes the following functions and properties:
85
90
  from Node core.
86
91
  - `.log` - The logger instance of the incoming request.
87
92
  - `.request` - The incoming request.
93
+ - `.getResponseTime()` - Deprecated, returns the amount of time passed
94
+ since the request was received by Fastify.
88
95
  - `.context` - Deprecated, access the [Request's context](./Request.md) property.
89
96
 
90
97
  ```js
@@ -110,6 +117,19 @@ fastify.get('/', {config: {foo: 'bar'}}, function (request, reply) {
110
117
 
111
118
  If not set via `reply.code`, the resulting `statusCode` will be `200`.
112
119
 
120
+ ### .elapsedTime
121
+ <a id="elapsedTime"></a>
122
+
123
+ Invokes the custom response time getter to calculate the amount of time passed
124
+ since the request was received by Fastify.
125
+
126
+ Note that unless this function is called in the [`onResponse`
127
+ hook](./Hooks.md#onresponse) it will always return `0`.
128
+
129
+ ```js
130
+ const milliseconds = reply.elapsedTime
131
+ ```
132
+
113
133
  ### .statusCode
114
134
  <a id="statusCode"></a>
115
135
 
@@ -327,7 +347,7 @@ reply.callNotFound()
327
347
  <a id="getResponseTime"></a>
328
348
 
329
349
  Invokes the custom response time getter to calculate the amount of time passed
330
- since the request was started.
350
+ since the request was received by Fastify.
331
351
 
332
352
  Note that unless this function is called in the [`onResponse`
333
353
  hook](./Hooks.md#onresponse) it will always return `0`.
@@ -336,6 +356,9 @@ hook](./Hooks.md#onresponse) it will always return `0`.
336
356
  const milliseconds = reply.getResponseTime()
337
357
  ```
338
358
 
359
+ *Note: This method is deprecated and will be removed in `fastify@5`.
360
+ Use the [.elapsedTime](#elapsedtime) property instead.*
361
+
339
362
  ### .type(contentType)
340
363
  <a id="type"></a>
341
364
 
@@ -735,6 +758,52 @@ fastify.get('/streams', function (request, reply) {
735
758
  })
736
759
  ```
737
760
 
761
+ #### ReadableStream
762
+ <a id="send-readablestream"></a>
763
+
764
+ `ReadableStream` will be treated as a node stream mentioned above,
765
+ the content is considered to be pre-serialized, so they will be
766
+ sent unmodified without response validation.
767
+
768
+ ```js
769
+ const fs = require('node:fs')
770
+ const { ReadableStream } = require('node:stream/web')
771
+ fastify.get('/streams', function (request, reply) {
772
+ const stream = fs.createReadStream('some-file')
773
+ reply.header('Content-Type', 'application/octet-stream')
774
+ reply.send(ReadableStream.from(stream))
775
+ })
776
+ ```
777
+
778
+ #### Response
779
+ <a id="send-response"></a>
780
+
781
+ `Response` allows to manage the reply payload, status code and
782
+ headers in one place. The payload provided inside `Response` is
783
+ considered to be pre-serialized, so they will be sent unmodified
784
+ without response validation.
785
+
786
+ Plese be aware when using `Response`, the status code and headers
787
+ will not directly reflect to `reply.statusCode` and `reply.getHeaders()`.
788
+ Such behavior is based on `Response` only allow `readonly` status
789
+ code and headers. The data is not allow to be bi-direction editing,
790
+ and may confuse when checking the `payload` in `onSend` hooks.
791
+
792
+ ```js
793
+ const fs = require('node:fs')
794
+ const { ReadableStream } = require('node:stream/web')
795
+ fastify.get('/streams', function (request, reply) {
796
+ const stream = fs.createReadStream('some-file')
797
+ const readableStream = ReadableStream.from(stream)
798
+ const response = new Response(readableStream, {
799
+ status: 200,
800
+ headers: { 'content-type': 'application/octet-stream' }
801
+ })
802
+ reply.send(response)
803
+ })
804
+ ```
805
+
806
+
738
807
  #### Errors
739
808
  <a id="errors"></a>
740
809
 
@@ -44,6 +44,7 @@ describes the properties available in that options object.
44
44
  - [`frameworkErrors`](#frameworkerrors)
45
45
  - [`clientErrorHandler`](#clienterrorhandler)
46
46
  - [`rewriteUrl`](#rewriteurl)
47
+ - [`useSemicolonDelimiter`](#usesemicolondelimiter)
47
48
  - [Instance](#instance)
48
49
  - [Server Methods](#server-methods)
49
50
  - [server](#server)
@@ -57,6 +58,7 @@ describes the properties available in that options object.
57
58
  - [routing](#routing)
58
59
  - [route](#route)
59
60
  - [hasRoute](#hasroute)
61
+ - [findRoute](#findroute)
60
62
  - [close](#close)
61
63
  - [decorate\*](#decorate)
62
64
  - [register](#register)
@@ -82,6 +84,7 @@ describes the properties available in that options object.
82
84
  - [setNotFoundHandler](#setnotfoundhandler)
83
85
  - [setErrorHandler](#seterrorhandler)
84
86
  - [setChildLoggerFactory](#setchildloggerfactory)
87
+ - [setGenReqId](#setGenReqId)
85
88
  - [addConstraintStrategy](#addconstraintstrategy)
86
89
  - [hasConstraintStrategy](#hasconstraintstrategy)
87
90
  - [printRoutes](#printroutes)
@@ -859,6 +862,31 @@ function rewriteUrl (req) {
859
862
  }
860
863
  ```
861
864
 
865
+ ### `useSemicolonDelimiter`
866
+ <a id="use-semicolon-delimiter"></a>
867
+
868
+ + Default `true`
869
+
870
+ Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which supports,
871
+ separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`.
872
+ This decision originated from [delvedor/find-my-way#76]
873
+ (https://github.com/delvedor/find-my-way/issues/76). Thus, this option will support
874
+ backwards compatiblilty for the need to split on `;`. To disable support for splitting
875
+ on `;` set `useSemicolonDelimiter` to `false`.
876
+
877
+ ```js
878
+ const fastify = require('fastify')({
879
+ useSemicolonDelimiter: true
880
+ })
881
+
882
+ fastify.get('/dev', async (request, reply) => {
883
+ // An example request such as `/dev;foo=bar`
884
+ // Will produce the following query params result `{ foo = 'bar' }`
885
+ return request.query
886
+ })
887
+ ```
888
+
889
+
862
890
  ## Instance
863
891
 
864
892
  ### Server Methods
@@ -1148,6 +1176,28 @@ if (routeExists === false) {
1148
1176
  }
1149
1177
  ```
1150
1178
 
1179
+ #### findRoute
1180
+ <a id="findRoute"></a>
1181
+
1182
+ Method to retrieve a route already registered to the internal router. It
1183
+ expects an object as the payload. `url` and `method` are mandatory fields. It
1184
+ is possible to also specify `constraints`.
1185
+ The method returns a route object or `null` if the route cannot be found.
1186
+
1187
+ ```js
1188
+ const route = fastify.findRoute({
1189
+ url: '/artists/:artistId',
1190
+ method: 'GET',
1191
+ constraints: { version: '1.0.0' } // optional
1192
+ })
1193
+
1194
+ if (route !== null) {
1195
+ // perform some route checks
1196
+ console.log(route.params) // `{artistId: ':artistId'}`
1197
+ }
1198
+ ```
1199
+
1200
+
1151
1201
  #### close
1152
1202
  <a id="close"></a>
1153
1203
 
@@ -1591,6 +1641,45 @@ const fastify = require('fastify')({
1591
1641
  The handler is bound to the Fastify instance and is fully encapsulated, so
1592
1642
  different plugins can set different logger factories.
1593
1643
 
1644
+ #### setGenReqId
1645
+ <a id="set-gen-req-id"></a>
1646
+
1647
+ `fastify.setGenReqId(function (rawReq))` Synchronous function for setting the request-id
1648
+ for additional Fastify instances. It will receive the _raw_ incoming request as a
1649
+ parameter. The provided function should not throw an Error in any case.
1650
+
1651
+ Especially in distributed systems, you may want to override the default ID
1652
+ generation behavior to handle custom ways of generating different IDs in
1653
+ order to handle different use cases. Such as observability or webhooks plugins.
1654
+
1655
+ For example:
1656
+ ```js
1657
+ const fastify = require('fastify')({
1658
+ genReqId: (req) => {
1659
+ return 'base'
1660
+ }
1661
+ })
1662
+
1663
+ fastify.register((instance, opts, done) => {
1664
+ instance.setGenReqId((req) => {
1665
+ // custom request ID for `/webhooks`
1666
+ return 'webhooks-id'
1667
+ })
1668
+ done()
1669
+ }, { prefix: '/webhooks' })
1670
+
1671
+ fastify.register((instance, opts, done) => {
1672
+ instance.setGenReqId((req) => {
1673
+ // custom request ID for `/observability`
1674
+ return 'observability-id'
1675
+ })
1676
+ done()
1677
+ }, { prefix: '/observability' })
1678
+ ```
1679
+
1680
+ The handler is bound to the Fastify instance and is fully encapsulated, so
1681
+ different plugins can set a different request ID.
1682
+
1594
1683
  #### addConstraintStrategy
1595
1684
  <a id="addConstraintStrategy"></a>
1596
1685
 
@@ -1920,6 +2009,7 @@ The properties that can currently be exposed are:
1920
2009
  - requestIdHeader
1921
2010
  - requestIdLogLabel
1922
2011
  - http2SessionTimeout
2012
+ - useSemicolonDelimiter
1923
2013
 
1924
2014
  ```js
1925
2015
  const { readFileSync } = require('node:fs')
@@ -23,6 +23,7 @@
23
23
  - [FSTDEP017](#FSTDEP017)
24
24
  - [FSTDEP018](#FSTDEP018)
25
25
  - [FSTDEP019](#FSTDEP019)
26
+ - [FSTDEP020](#FSTDEP020)
26
27
 
27
28
 
28
29
  ## Warnings
@@ -75,3 +76,4 @@ Deprecation codes are further supported by the Node.js CLI options:
75
76
  | <a id="FSTDEP017">FSTDEP017</a> | You are accessing the deprecated `request.routerPath` property. | Use `request.routeOptions.url`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
76
77
  | <a id="FSTDEP018">FSTDEP018</a> | You are accessing the deprecated `request.routerMethod` property. | Use `request.routeOptions.method`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
77
78
  | <a id="FSTDEP019">FSTDEP019</a> | You are accessing the deprecated `reply.context` property. | Use `reply.routeOptions.config` or `reply.routeOptions.schema`. | [#5032](https://github.com/fastify/fastify/pull/5032) [#5084](https://github.com/fastify/fastify/pull/5084) |
79
+ | <a id="FSTDEP020">FSTDEP020</a> | You are using the deprecated `reply.getReponseTime()` method. | Use the `reply.elapsedTime` property instead. | [#5263](https://github.com/fastify/fastify/pull/5263) |
package/fastify.d.ts CHANGED
@@ -14,7 +14,7 @@ import { FastifyRequestContext, FastifyContextConfig, FastifyReplyContext } from
14
14
  import { FastifyErrorCodes } from './types/errors'
15
15
  import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onListenAsyncHookHandler, onListenHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler } from './types/hooks'
16
16
  import { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
17
- import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel, Bindings, ChildLoggerOptions } from './types/logger'
17
+ import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel } from './types/logger'
18
18
  import { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
19
19
  import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './types/register'
20
20
  import { FastifyReply } from './types/reply'
@@ -109,6 +109,7 @@ declare namespace fastify {
109
109
  allowUnsafeRegex?: boolean,
110
110
  requestIdHeader?: string | false,
111
111
  requestIdLogLabel?: string;
112
+ useSemicolonDelimiter?: boolean,
112
113
  jsonShorthand?: boolean;
113
114
  genReqId?: (req: RawRequestDefaultExpression<RawServer>) => string,
114
115
  trustProxy?: boolean | string | string[] | number | TrustProxyFunction,
@@ -238,4 +239,4 @@ declare function fastify<
238
239
 
239
240
  // CJS export
240
241
  // const fastify = require('fastify')
241
- export = fastify
242
+ export = fastify
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.25.2'
3
+ const VERSION = '4.26.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('node:http')
@@ -28,7 +28,8 @@ const {
28
28
  kSchemaErrorFormatter,
29
29
  kErrorHandler,
30
30
  kKeepAliveConnections,
31
- kChildLoggerFactory
31
+ kChildLoggerFactory,
32
+ kGenReqId
32
33
  } = require('./lib/symbols.js')
33
34
 
34
35
  const { createServer, compileValidateHTTPVersion } = require('./lib/server')
@@ -42,7 +43,7 @@ const SchemaController = require('./lib/schema-controller')
42
43
  const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
43
44
  const { createLogger, createChildLogger, defaultChildLoggerFactory } = require('./lib/logger')
44
45
  const pluginUtils = require('./lib/pluginUtils')
45
- const { reqIdGenFactory } = require('./lib/reqIdGenFactory')
46
+ const { getGenReqId, reqIdGenFactory } = require('./lib/reqIdGenFactory')
46
47
  const { buildRouting, validateBodyLimitOption } = require('./lib/route')
47
48
  const build404 = require('./lib/fourOhFour')
48
49
  const getSecuredInitialConfig = require('./lib/initialConfigValidation')
@@ -138,7 +139,6 @@ function fastify (options) {
138
139
  options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
139
140
  options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
140
141
  options.logger = logger
141
- options.genReqId = genReqId
142
142
  options.requestIdHeader = requestIdHeader
143
143
  options.requestIdLogLabel = requestIdLogLabel
144
144
  options.disableRequestLogging = disableRequestLogging
@@ -181,7 +181,8 @@ function fastify (options) {
181
181
  caseSensitive: options.caseSensitive,
182
182
  allowUnsafeRegex: options.allowUnsafeRegex || defaultInitOptions.allowUnsafeRegex,
183
183
  buildPrettyMeta: defaultBuildPrettyMeta,
184
- querystringParser: options.querystringParser
184
+ querystringParser: options.querystringParser,
185
+ useSemicolonDelimiter: options.useSemicolonDelimiter ?? defaultInitOptions.useSemicolonDelimiter
185
186
  }
186
187
  })
187
188
 
@@ -247,6 +248,7 @@ function fastify (options) {
247
248
  [pluginUtils.kRegisteredPlugins]: [],
248
249
  [kPluginNameChain]: ['fastify'],
249
250
  [kAvvioBoot]: null,
251
+ [kGenReqId]: genReqId,
250
252
  // routing method
251
253
  routing: httpHandler,
252
254
  getDefaultRoute: router.getDefaultRoute.bind(router),
@@ -285,6 +287,9 @@ function fastify (options) {
285
287
  hasRoute: function _route (options) {
286
288
  return router.hasRoute.call(this, { options })
287
289
  },
290
+ findRoute: function _findRoute (options) {
291
+ return router.findRoute(options)
292
+ },
288
293
  // expose logger instance
289
294
  log: logger,
290
295
  // type provider
@@ -300,6 +305,8 @@ function fastify (options) {
300
305
  setSchemaController,
301
306
  setReplySerializer,
302
307
  setSchemaErrorFormatter,
308
+ // set generated request id
309
+ setGenReqId,
303
310
  // custom parsers
304
311
  addContentTypeParser: ContentTypeParser.helpers.addContentTypeParser,
305
312
  hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser,
@@ -396,6 +403,10 @@ function fastify (options) {
396
403
  get () {
397
404
  return this[kErrorHandler].func
398
405
  }
406
+ },
407
+ genReqId: {
408
+ configurable: true,
409
+ get () { return this[kGenReqId] }
399
410
  }
400
411
  })
401
412
 
@@ -739,7 +750,7 @@ function fastify (options) {
739
750
 
740
751
  function onBadUrl (path, req, res) {
741
752
  if (frameworkErrors) {
742
- const id = genReqId(req)
753
+ const id = getGenReqId(onBadUrlContext.server, req)
743
754
  const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
744
755
 
745
756
  const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
@@ -764,7 +775,7 @@ function fastify (options) {
764
775
  return function onAsyncConstraintError (err) {
765
776
  if (err) {
766
777
  if (frameworkErrors) {
767
- const id = genReqId(req)
778
+ const id = getGenReqId(onBadUrlContext.server, req)
768
779
  const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
769
780
 
770
781
  const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
@@ -868,6 +879,13 @@ function fastify (options) {
868
879
  router.routing(req, res, buildAsyncConstraintCallback(isAsync, req, res))
869
880
  }
870
881
  }
882
+
883
+ function setGenReqId (func) {
884
+ throwIfAlreadyStarted('Cannot call "setGenReqId"!')
885
+
886
+ this[kGenReqId] = reqIdGenFactory(this[kOptions].requestIdHeader, func)
887
+ return this
888
+ }
871
889
  }
872
890
 
873
891
  fastify.errorCodes = errorCodes