fastify 6.0.0-alpha.4 → 6.0.0-alpha.6

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 (63) hide show
  1. package/README.md +1 -0
  2. package/SECURITY.md +6 -0
  3. package/build/build-validation.js +2 -0
  4. package/docs/Guides/Ecosystem.md +12 -53
  5. package/docs/Guides/Migration-Guide-V5.md +2 -2
  6. package/docs/Guides/Serverless.md +33 -10
  7. package/docs/Reference/Errors.md +13 -2
  8. package/docs/Reference/Hooks.md +13 -0
  9. package/docs/Reference/Reply.md +787 -681
  10. package/docs/Reference/Request.md +308 -104
  11. package/docs/Reference/Routes.md +6 -2
  12. package/docs/Reference/Server.md +41 -4
  13. package/docs/Reference/Validation-and-Serialization.md +48 -1
  14. package/docs/Reference/Warnings.md +2 -0
  15. package/fastify.d.ts +1 -0
  16. package/fastify.js +35 -1
  17. package/lib/config-validator.js +102 -73
  18. package/lib/content-type-parser.js +35 -14
  19. package/lib/content-type.js +4 -4
  20. package/lib/context.js +2 -1
  21. package/lib/decorate.js +4 -3
  22. package/lib/error-handler.js +21 -4
  23. package/lib/error-status.js +4 -2
  24. package/lib/errors.js +15 -14
  25. package/lib/handle-request.js +7 -20
  26. package/lib/reply.js +18 -13
  27. package/lib/request.js +12 -7
  28. package/lib/route.js +40 -7
  29. package/lib/schemas.js +44 -32
  30. package/lib/validation.js +67 -10
  31. package/lib/warnings.js +10 -1
  32. package/package.json +8 -3
  33. package/test/child-logger-factory.test.js +25 -0
  34. package/test/close-disposable.test.js +154 -0
  35. package/test/constrained-routes.test.js +4 -2
  36. package/test/content-parser.test.js +99 -0
  37. package/test/decorator.test.js +29 -0
  38. package/test/diagnostics-channel/error-status.test.js +35 -2
  39. package/test/handler-timeout.test.js +224 -0
  40. package/test/internals/all.test.js +5 -0
  41. package/test/internals/errors.test.js +19 -20
  42. package/test/internals/initial-config.test.js +2 -0
  43. package/test/internals/reply-serialize.test.js +20 -0
  44. package/test/internals/reply.test.js +30 -1
  45. package/test/internals/request.test.js +50 -0
  46. package/test/internals/server.test.js +6 -4
  47. package/test/reply-error.test.js +82 -0
  48. package/test/reply-media-type.test.js +57 -0
  49. package/test/reply-trailers.test.js +159 -1
  50. package/test/rfc-10008.test.js +6 -9
  51. package/test/router-compile.test.js +241 -0
  52. package/test/schema-feature.test.js +1 -1
  53. package/test/schema-serialization.test.js +120 -7
  54. package/test/schema-validation.test.js +251 -1
  55. package/test/types/errors.tst.ts +0 -1
  56. package/test/types/fastify.tst.ts +9 -0
  57. package/test/types/instance.tst.ts +1 -1
  58. package/test/types/route.tst.ts +37 -0
  59. package/test/types/using.tst.ts +20 -0
  60. package/test/validation-error-handling.test.js +21 -1
  61. package/types/errors.d.ts +0 -1
  62. package/types/instance.d.ts +9 -5
  63. package/types/route.d.ts +4 -2
@@ -1,92 +1,71 @@
1
1
  <h1 align="center">Fastify</h1>
2
2
 
3
3
  ## Request
4
+ - [Introduction](#introduction)
5
+ - [Request](#request-object)
6
+ - [Properties](#properties)
7
+ - [.body](#body)
8
+ - [.query](#query)
9
+ - [.params](#params)
10
+ - [.headers](#headers)
11
+ - [.id](#id)
12
+ - [.log](#log)
13
+ - [.method](#method)
14
+ - [.url](#url)
15
+ - [.routeOptions](#routeoptions)
16
+ - [.server](#server)
17
+ - [.raw](#raw)
18
+ - [.ip](#ip)
19
+ - [.ips](#ips)
20
+ - [.host](#host)
21
+ - [.hostname](#hostname)
22
+ - [.port](#port)
23
+ - [.protocol](#protocol)
24
+ - [.originalUrl](#originalurl)
25
+ - [.mediaType](#mediatype)
26
+ - [.signal](#signal)
27
+ - [.socket](#socket)
28
+ - [.is404](#is404)
29
+ - [.validationError](#validationerror)
30
+ - [Methods](#methods)
31
+ - [.getDecorator(name)](#getdecorator)
32
+ - [.setDecorator(name, value)](#setdecorator)
33
+ - [.getValidationFunction(schema | httpPart)](#getvalidationfunction)
34
+ - [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema)
35
+ - [.validateInput(data, [schema | httpPart], [httpPart])](#validate)
36
+
37
+ ### Introduction
38
+ <a id="introduction"></a>
39
+
4
40
  The first parameter of the handler function is `Request`.
5
41
 
6
42
  Request is a core Fastify object containing the following fields:
7
- - `query` - The parsed querystring, its format is specified by
8
- [`querystringParser`](./Server.md#querystringparser).
9
- - `body` - The request payload, see [Content-Type Parser](./ContentTypeParser.md)
10
- for details on what request payloads Fastify natively parses and how to support
11
- other content types.
12
- - `params` - The params matching the URL. Values are percent-decoded
13
- (for example `%20` becomes a space, and `%2f` becomes `/`). Decoded
14
- values may contain `.`, `..`, `/`, or other characters; treat them as
15
- untrusted input. See the security note below and
16
- [Routes - Url building](./Routes.md#url-building).
43
+ - `query` - The parsed querystring.
44
+ - `body` - The request payload.
45
+ - `params` - The params matching the URL.
17
46
  - [`headers`](#headers) - The headers getter and setter.
18
47
  - `raw` - The incoming HTTP request from Node core.
19
- - `server` - The Fastify server instance, scoped to the current
20
- [encapsulation context](./Encapsulation.md).
48
+ - `server` - The Fastify server instance.
21
49
  - `id` - The request ID.
22
50
  - `log` - The logger instance of the incoming request.
23
- - `ip` - The IP address of the incoming request. This value is taken from
24
- `socket.remoteAddress` (or from `X-Forwarded-For` when
25
- [`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
26
- - `ips` - An array of IP addresses, ordered from closest to furthest, from
27
- `X-Forwarded-For` (only when
28
- [`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
29
- - `host` - The host of the incoming request (derived from `X-Forwarded-Host`
30
- when [`trustProxy`](./Server.md#factory-trust-proxy) is enabled). For HTTP/2
31
- compatibility, it returns `:authority` if no host header exists. The host
32
- header may return an empty string if `requireHostHeader` is `false`, not
33
- provided with HTTP/1.0, or removed by schema validation.
51
+ - `ip` - The IP address of the incoming request.
52
+ - `ips` - An array of IP addresses from `X-Forwarded-For`.
53
+ - `host` - The host of the incoming request.
34
54
  - `hostname` - The hostname parsed from `request.host`.
35
- - `port` - The port parsed from `request.host`, which may refer to the port the
36
- server is listening on.
37
- - `protocol` - The protocol of the incoming request (`https` or `http`). This
38
- value comes from `socket.encrypted` (or `X-Forwarded-Proto` when
39
- [`trustProxy`](./Server.md#factory-trust-proxy) is enabled).
40
-
41
- > ⚠️ Security:
42
- > `request.params`, `request.query`, `request.headers`, and `request.body`
43
- > are untrusted network input. Route parameter values are percent-decoded
44
- > before your handler runs, so a segment like `..%2ffile` becomes `../file`
45
- > in `request.params`. Do not use parameter values as filesystem paths,
46
- > template names, or redirect targets without validating or containing
47
- > them. Prefer [`@fastify/static`](https://github.com/fastify/fastify-static)
48
- > (or `reply.sendFile`) when serving files from a root directory.
49
- >
50
- > `request.ip`, `request.ips`, `request.host`, `request.hostname`,
51
- > `request.port`, and `request.protocol` come from request metadata
52
- > (socket and/or forwarding headers) and should also be treated as
53
- > untrusted input. Fastify does not perform security validation for
54
- > business logic. If these values are used in security-sensitive decisions,
55
- > they must be validated explicitly (for example: trusted proxy
56
- > configuration, allow-lists, strict parsing, and normalization).
57
-
55
+ - `port` - The port parsed from `request.host`.
56
+ - `protocol` - The protocol of the incoming request (`https` or `http`).
58
57
  - `method` - The method of the incoming request.
59
58
  - `url` - The URL of the incoming request.
60
- - `originalUrl` - Similar to `url`, allows access to the original `url` in
61
- case of internal re-routing.
62
- - `mediaType` - The media type extracted from `Content-Type` header. When `Content-Type`
63
- header is missing, it will return `undefined`.
59
+ - `originalUrl` - The original URL of the incoming request.
60
+ - `mediaType` - The media type extracted from `Content-Type` header.
64
61
  - `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
65
62
  - `socket` - The underlying connection of the incoming request.
66
- - `signal` - An `AbortSignal` that aborts when the handler timeout
67
- fires or the client disconnects. Created lazily on first access, so
68
- there is zero overhead when not used. When
69
- [`handlerTimeout`](./Server.md#factory-handler-timeout) is configured,
70
- the signal is pre-created and also aborts on timeout. Pass it to
71
- `fetch()`, database queries, or any API accepting a `signal` option
72
- for cooperative cancellation. On timeout, `signal.reason` is the
73
- `FST_ERR_HANDLER_TIMEOUT` error; on client disconnect it is a generic
74
- `AbortError`. Check `signal.reason.code` to distinguish the two cases.
63
+ - `signal` - An `AbortSignal` that aborts on handler timeout or client
64
+ disconnect.
75
65
  - `routeOptions` - The route [`option`](./Routes.md#routes-options) object.
76
- - `bodyLimit` - Either server limit or route limit.
77
- - `handlerTimeout` - The handler timeout configured for this route.
78
- - `config` - The [`config`](./Routes.md#routes-config) object for this route.
79
- - `method` - The HTTP method for the route.
80
- - `url` - The path of the URL to match this route.
81
- - `handler` - The handler for this route.
82
- - `attachValidation` - Attach `validationError` to request (if there is
83
- a schema defined).
84
- - `logLevel` - Log level defined for this route.
85
- - `schema` - The JSON schemas definition for this route.
86
- - `version` - A semver compatible string that defines the version of the endpoint.
87
- - `exposeHeadRoute` - Creates a sibling HEAD route for any GET routes.
88
- - `prefixTrailingSlash` - String used to determine how to handle passing `/`
89
- as a route with a prefix.
66
+ - `validationError` - The validation error, when `attachValidation` is set.
67
+ - `getDecorator(name)` - Returns the value of a request decorator.
68
+ - `setDecorator(name, value)` - Sets the value of a request decorator.
90
69
  - [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
91
70
  Returns a validation function for the specified schema or HTTP part, if
92
71
  set or cached.
@@ -99,29 +78,6 @@ Request is a core Fastify object containing the following fields:
99
78
  `true` if the input is valid, `false` otherwise. If `httpPart` is provided,
100
79
  the function uses the validator for that HTTP part. Defaults to `null`.
101
80
 
102
- ### Headers
103
-
104
- The `request.headers` is a getter that returns an object with the headers of the
105
- incoming request. Set custom headers as follows:
106
-
107
- ```js
108
- request.headers = {
109
- 'foo': 'bar',
110
- 'baz': 'qux'
111
- }
112
- ```
113
-
114
- This operation adds new values to the request headers, accessible via
115
- `request.headers.bar`. Standard request headers remain accessible via
116
- `request.raw.headers`.
117
-
118
- For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added
119
- to headers on `not found` routes.
120
-
121
- > ℹ️ Note:
122
- > Schema validation may mutate the `request.headers` and
123
- > `request.raw.headers` objects, causing the headers to become empty.
124
-
125
81
  ```js
126
82
  fastify.post('/:params', options, function (request, reply) {
127
83
  console.log(request.body)
@@ -151,12 +107,260 @@ fastify.post('/:params', options, function (request, reply) {
151
107
  request.log.info('some info')
152
108
  })
153
109
  ```
154
- ### .getValidationFunction(schema | httpPart)
110
+
111
+ > ⚠️ Security:
112
+ > `request.params`, `request.query`, `request.headers`, and `request.body`
113
+ > are untrusted network input. Route parameter values are percent-decoded
114
+ > before your handler runs, so a segment like `..%2ffile` becomes `../file`
115
+ > in `request.params`. Do not use parameter values as filesystem paths,
116
+ > template names, or redirect targets without validating or containing
117
+ > them. Prefer [`@fastify/static`](https://github.com/fastify/fastify-static)
118
+ > (or `reply.sendFile`) when serving files from a root directory.
119
+ >
120
+ > `request.ip`, `request.ips`, `request.host`, `request.hostname`,
121
+ > `request.port`, and `request.protocol` come from request metadata
122
+ > (socket and/or forwarding headers) and should also be treated as
123
+ > untrusted input. Fastify does not perform security validation for
124
+ > business logic. If these values are used in security-sensitive decisions,
125
+ > they must be validated explicitly (for example: trusted proxy
126
+ > configuration, allow-lists, strict parsing, and normalization).
127
+
128
+ ### Request
129
+ <a id="request-object"></a>
130
+
131
+ #### Properties
132
+ <a id="properties"></a>
133
+
134
+ ##### .body
135
+
136
+ The request payload. See [Content-Type Parser](./ContentTypeParser.md) for
137
+ details on what request payloads Fastify natively parses and how to support
138
+ other content types.
139
+
140
+ ##### .query
141
+
142
+ The parsed querystring. Its format is specified by
143
+ [`querystringParser`](./Server.md#querystringparser).
144
+
145
+ ##### .params
146
+
147
+ The params matching the URL. Values are percent-decoded (for example `%20`
148
+ becomes a space, and `%2f` becomes `/`). Decoded values may contain `.`, `..`,
149
+ `/`, or other characters; treat them as untrusted input. See the
150
+ [security note](#introduction) and
151
+ [Routes - Url building](./Routes.md#url-building).
152
+
153
+ ##### .headers
154
+
155
+ The `request.headers` is a getter that returns an object with the headers of the
156
+ incoming request. Set custom headers as follows:
157
+
158
+ ```js
159
+ request.headers = {
160
+ 'foo': 'bar',
161
+ 'baz': 'qux'
162
+ }
163
+ ```
164
+
165
+ This operation adds new values to the request headers, accessible via
166
+ `request.headers.foo`. Standard request headers remain accessible via
167
+ `request.raw.headers`.
168
+
169
+ For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added
170
+ to headers on `not found` routes.
171
+
172
+ > ℹ️ Note:
173
+ > Schema validation may mutate the `request.headers` and
174
+ > `request.raw.headers` objects, causing the headers to become empty.
175
+
176
+ > ℹ️ Note:
177
+ > The setter is additive, so it cannot be used to *remove* a header, and a
178
+ > `headers` schema validator's synchronous `{ value }` result is applied through
179
+ > this same setter. `request.headers` is therefore the incoming request's
180
+ > headers (plus any additive values), not a sanitized or authoritative view. If
181
+ > your application needs an allow-listed header subset, build and consume it
182
+ > explicitly from the validated data or from `request.raw.headers`.
183
+
184
+ ##### .id
185
+
186
+ The request ID. It is generated by [`genReqId`](./Server.md#genreqid), or read
187
+ from the header configured with [`requestIdHeader`](./Server.md#requestidheader)
188
+ when the incoming request includes it.
189
+
190
+ ##### .log
191
+
192
+ The logger instance of the incoming request. By default, it is a child logger of
193
+ the server logger that adds the request ID (`reqId`) to every log line. See
194
+ [`childLoggerFactory`](./Server.md#childLoggerFactory) to customize it.
195
+
196
+ ##### .method
197
+
198
+ The method of the incoming request.
199
+
200
+ ##### .url
201
+
202
+ The URL of the incoming request.
203
+
204
+ ##### .routeOptions
205
+
206
+ The route [`option`](./Routes.md#routes-options) object.
207
+ - `bodyLimit` - Either server limit or route limit.
208
+ - `handlerTimeout` - The handler timeout configured for this route.
209
+ - `config` - The [`config`](./Routes.md#routes-config) object for this route.
210
+ - `method` - The HTTP method for the route.
211
+ - `url` - The path of the URL to match this route.
212
+ - `handler` - The handler for this route.
213
+ - `attachValidation` - Attach `validationError` to request (if there is
214
+ a schema defined).
215
+ - `logLevel` - Log level defined for this route.
216
+ - `schema` - The JSON schemas definition for this route.
217
+ - `version` - A semver compatible string that defines the version of the
218
+ endpoint.
219
+ - `exposeHeadRoute` - Creates a sibling HEAD route for any GET routes.
220
+ - `prefixTrailingSlash` - String used to determine how to handle passing `/`
221
+ as a route with a prefix.
222
+
223
+ ##### .server
224
+
225
+ The Fastify server instance, scoped to the current
226
+ [encapsulation context](./Encapsulation.md).
227
+
228
+ ##### .raw
229
+
230
+ The incoming HTTP request from Node core.
231
+
232
+ ##### .ip
233
+
234
+ The IP address of the incoming request. This value is taken from
235
+ `socket.remoteAddress` (or from `X-Forwarded-For` when
236
+ [`trustProxy`](./Server.md#factory-trust-proxy) is enabled). It is `undefined`
237
+ when the underlying socket is not available.
238
+
239
+ ##### .ips
240
+
241
+ An array of IP addresses, ordered from closest to furthest, from
242
+ `X-Forwarded-For` (only when [`trustProxy`](./Server.md#factory-trust-proxy) is
243
+ enabled). It is `undefined` when `trustProxy` is not enabled.
244
+
245
+ ##### .host
246
+
247
+ The host of the incoming request (derived from `X-Forwarded-Host` when
248
+ [`trustProxy`](./Server.md#factory-trust-proxy) is enabled). For HTTP/2
249
+ compatibility, it returns `:authority` if no host header exists. The host header
250
+ may return an empty string if `requireHostHeader` is `false`, not provided with
251
+ HTTP/1.0, or removed by schema validation.
252
+
253
+ ##### .hostname
254
+
255
+ The hostname parsed from `request.host`. For IPv6 hosts, the brackets are kept
256
+ (for example, `[::1]`).
257
+
258
+ ##### .port
259
+
260
+ The port parsed from `request.host`, which may refer to the port the server is
261
+ listening on. It is `null` when the host does not include a port.
262
+
263
+ ##### .protocol
264
+
265
+ The protocol of the incoming request (`https` or `http`). This value comes from
266
+ `socket.encrypted` (or `X-Forwarded-Proto` when
267
+ [`trustProxy`](./Server.md#factory-trust-proxy) is enabled). It is `undefined`
268
+ when the underlying socket is not available.
269
+
270
+ ##### .originalUrl
271
+
272
+ Similar to `url`, allows access to the original `url` in case of internal
273
+ re-routing.
274
+
275
+ ##### .mediaType
276
+
277
+ The media type extracted from `Content-Type` header. When `Content-Type` header
278
+ is missing, it will return `undefined`.
279
+
280
+ ##### .signal
281
+
282
+ An `AbortSignal` that aborts when the handler timeout fires or the client
283
+ disconnects. Created lazily on first access, so there is zero overhead when not
284
+ used. When [`handlerTimeout`](./Server.md#factory-handler-timeout) is
285
+ configured, the signal is pre-created and also aborts on timeout. Pass it to
286
+ `fetch()`, database queries, or any API accepting a `signal` option for
287
+ cooperative cancellation. On timeout, `signal.reason` is the
288
+ `FST_ERR_HANDLER_TIMEOUT` error; on client disconnect it is a generic
289
+ `AbortError`. Check `signal.reason.code` to distinguish the two cases.
290
+
291
+ ##### .socket
292
+
293
+ The underlying connection of the incoming request.
294
+
295
+ ##### .is404
296
+
297
+ `true` if request is being handled by 404 handler, `false` otherwise.
298
+
299
+ ##### .validationError
300
+
301
+ The validation error of the request. It is set only when the route has the
302
+ [`attachValidation`](./Routes.md#routes-options) option enabled and the
303
+ validation fails; otherwise it is `undefined`. In that case, Fastify calls the
304
+ handler instead of replying with a `400` error. See
305
+ [Validation and Serialization](./Validation-and-Serialization.md#error-handling)
306
+ for the properties of the error object.
307
+
308
+ ```js
309
+ fastify.post('/', { schema, attachValidation: true }, function (request, reply) {
310
+ if (request.validationError) {
311
+ // `request.validationError.validationContext` is the failed part,
312
+ // for example `body`
313
+ reply.code(422).send(request.validationError)
314
+ return
315
+ }
316
+ reply.send({ hello: 'world' })
317
+ })
318
+ ```
319
+
320
+ #### Methods
321
+ <a id="methods"></a>
322
+
323
+ ##### .getDecorator(name)
324
+ <a id="getdecorator"></a>
325
+
326
+ Returns the value of a request decorator declared with
327
+ [`decorateRequest`](./Decorators.md#decoraterequestname-value-dependencies).
328
+ If the decorator is a function, it is returned bound to the request. It throws
329
+ an `FST_ERR_DEC_UNDECLARED` error if the decorator has not been declared. See
330
+ [`getDecorator`](./Decorators.md#getdecoratorname) for more details.
331
+
332
+ ```js
333
+ fastify.decorateRequest('user', null)
334
+
335
+ fastify.get('/', function (request, reply) {
336
+ const user = request.getDecorator('user')
337
+ reply.send({ user })
338
+ })
339
+ ```
340
+
341
+ ##### .setDecorator(name, value)
342
+ <a id="setdecorator"></a>
343
+
344
+ Sets the value of a request decorator declared with
345
+ [`decorateRequest`](./Decorators.md#decoraterequestname-value-dependencies).
346
+ It throws an `FST_ERR_DEC_UNDECLARED` error if the decorator has not been
347
+ declared. See [`setDecorator`](./Decorators.md#setdecoratorname-value) for more
348
+ details.
349
+
350
+ ```js
351
+ fastify.decorateRequest('user', null)
352
+
353
+ fastify.addHook('preHandler', async (request) => {
354
+ request.setDecorator('user', 'Bob Dylan')
355
+ })
356
+ ```
357
+
358
+ ##### .getValidationFunction(schema | httpPart)
155
359
  <a id="getvalidationfunction"></a>
156
360
 
157
361
  By calling this function with a provided `schema` or `httpPart`, it returns a
158
362
  `validation` function to validate diverse inputs. It returns `undefined` if no
159
- serialization function is found using the provided inputs.
363
+ validation function is found using the provided inputs.
160
364
 
161
365
  This function has an `errors` property. Errors encountered during the last
162
366
  validation are assigned to `errors`.
@@ -182,10 +386,10 @@ console.log(validate({ foo: 0.5 })) // false
182
386
  console.log(validate.errors) // validation errors
183
387
  ```
184
388
 
185
- See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
389
+ See [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema)
186
390
  for more information on compiling validation schemas.
187
391
 
188
- ### .compileValidationSchema(schema, [httpPart])
392
+ ##### .compileValidationSchema(schema, [httpPart])
189
393
  <a id="compilevalidationschema"></a>
190
394
 
191
395
  This function compiles a validation schema and returns a function to validate data.
@@ -223,8 +427,8 @@ const validate = request
223
427
  type: 'string'
224
428
  }
225
429
  }
226
- }, 200)
227
- console.log(validate({ hello: 'world' })) // false
430
+ }, 'body')
431
+ console.log(validate({ foo: {} })) // false
228
432
  console.log(validate.errors) // validation errors
229
433
  ```
230
434
 
@@ -272,7 +476,7 @@ const newValidate = request.compileValidationSchema(newSchema)
272
476
  console.log(newValidate === validate) // false
273
477
  ```
274
478
 
275
- ### .validateInput(data, [schema | httpPart], [httpPart])
479
+ ##### .validateInput(data, [schema | httpPart], [httpPart])
276
480
  <a id="validate"></a>
277
481
 
278
482
  This function validates the input based on the provided schema or HTTP part. If
@@ -310,5 +514,5 @@ request
310
514
  .validateInput({ hello: 'world'}, 'query') // false
311
515
  ```
312
516
 
313
- See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
517
+ See [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema)
314
518
  for more information on compiling validation schemas.
@@ -32,7 +32,7 @@ fastify.route(options)
32
32
  <a id="options"></a>
33
33
 
34
34
  * `method`: currently it supports `GET`, `HEAD`, `TRACE`, `DELETE`,
35
- `OPTIONS`, `PATCH`, `PUT` and `POST`. To accept more methods,
35
+ `OPTIONS`, `PATCH`, `PUT`, `POST` and `QUERY`. To accept more methods,
36
36
  the [`addHttpMethod`](./Server.md#addHttpMethod) must be used.
37
37
  It could also be an array of methods.
38
38
  * `url`: the path of the URL to match this route (alias: `path`).
@@ -41,7 +41,7 @@ fastify.route(options)
41
41
  [here](./Validation-and-Serialization.md) for more info.
42
42
 
43
43
  * `body`: validates the body of the request if it is a POST, PUT, PATCH,
44
- TRACE, SEARCH, PROPFIND, PROPPATCH or LOCK method.
44
+ TRACE, SEARCH, PROPFIND, PROPPATCH, LOCK or QUERY method.
45
45
  * `querystring` or `query`: validates the querystring. This can be a complete
46
46
  JSON Schema object, with the property `type` of `object` and `properties`
47
47
  object of parameters, or simply the values of what would be contained in the
@@ -198,6 +198,10 @@ The above route declaration is more *Hapi*-like, but if you prefer an
198
198
 
199
199
  `fastify.patch(path, [options], handler)`
200
200
 
201
+ `fastify.query(path, [options], handler)`
202
+
203
+ > The `QUERY` method (RFC 10008) requires a `Content-Type` header.
204
+
201
205
  Example:
202
206
  ```js
203
207
  const opts = {
@@ -41,6 +41,7 @@ describes the properties available in that options object.
41
41
  - [`allowUnsafeRegex`](#allowunsaferegex)
42
42
  - [`buildPrettyMeta`](#buildprettymeta)
43
43
  - [`caseSensitive`](#casesensitive)
44
+ - [`compile`](#compile)
44
45
  - [`constraints`](#constraints)
45
46
  - [`defaultRoute`](#defaultroute)
46
47
  - [`ignoreDuplicateSlashes`](#ignoreduplicateslashes)
@@ -213,7 +214,7 @@ ignored.
213
214
 
214
215
  Defines the maximum number of milliseconds for receiving the entire request from
215
216
  the client. See [`server.requestTimeout`
216
- property](https://nodejs.org/dist/latest/docs/api/http.html#servertimeout)
217
+ property](https://nodejs.org/dist/latest/docs/api/http.html#serverrequesttimeout)
217
218
  to understand the effect of this option.
218
219
 
219
220
  When `serverFactory` option is specified, this option is ignored.
@@ -920,6 +921,36 @@ fastify.get('/user/:username', (request, reply) => {
920
921
  })
921
922
  ```
922
923
 
924
+ ### `compile`
925
+ <a id="compile"></a>
926
+
927
+ + Default: `false`
928
+
929
+ When `true`, Fastify calls the
930
+ [`compile()`](https://github.com/delvedor/find-my-way#compiler-mode) method of
931
+ `find-my-way` once all the routes are registered, right before the
932
+ [`onReady`](./Hooks.md#onready) hooks run. This applies to both the main
933
+ router and the router used for [not found handlers](#set-not-found-handler).
934
+ Each HTTP method's routing tree is
935
+ turned into generated JavaScript instead of being walked for every request,
936
+ which makes route lookups faster. Matching semantics are the same as with the
937
+ default tree walk.
938
+
939
+ ```js
940
+ const fastify = require('fastify')({
941
+ routerOptions: {
942
+ compile: true
943
+ }
944
+ })
945
+ ```
946
+
947
+ Keep in mind that:
948
+
949
+ + the compiled matcher works on the raw request URL; URLs containing
950
+ percent-encoded characters fall back to the decoded path and are not faster;
951
+ + every route generates its own code, so applications with thousands of routes
952
+ produce a large amount of JavaScript, which needs to warm up per route.
953
+
923
954
  ### `constraints`
924
955
  <a id="constraints"></a>
925
956
 
@@ -1044,9 +1075,14 @@ multi) routes by using `maxParamLength` option; the default value is 100
1044
1075
  characters. If the maximum length limit is reached, the not found route will
1045
1076
  be invoked.
1046
1077
 
1047
- This can be useful especially if you have a regex-based route, protecting you
1048
- against [ReDoS
1049
- attacks](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS).
1078
+ For regex routes, the limit applies to the values captured by the regular
1079
+ expression, and it is checked only after the expression has run against the
1080
+ whole path segment. `maxParamLength` therefore does not limit the input a route
1081
+ regex processes and does not protect against [ReDoS
1082
+ attacks](https://community.owasp.org/attacks/Regular_expression_Denial_of_Service_-_ReDoS).
1083
+ To guard against ReDoS, keep [`allowUnsafeRegex`](#allow-unsafe-regex)
1084
+ disabled so that potentially catastrophic regular expressions are rejected when
1085
+ the route is registered.
1050
1086
 
1051
1087
 
1052
1088
  ### `onBadUrl`
@@ -2382,6 +2418,7 @@ The properties that can currently be exposed are:
2382
2418
  - allowUnsafeRegex
2383
2419
  - buildPrettyMeta
2384
2420
  - caseSensitive
2421
+ - compile
2385
2422
  - constraints
2386
2423
  - defaultRoute
2387
2424
  - ignoreDuplicateSlashes
@@ -167,6 +167,22 @@ parameters at the top level.
167
167
  > ℹ For using the latest Ajv (v8), refer to the
168
168
  > [`schemaController`](./Server.md#schema-controller) section.
169
169
 
170
+ ##### Header name case
171
+
172
+ Node.js exposes request header names in lowercase. Fastify normalizes header
173
+ names in a `headers` schema to lowercase before compilation, so assertions
174
+ written in the canonical header-name case still match the request, for example
175
+ `required: ['X-Api-Key']`, `dependencies`, and a `propertyNames` deny-list that
176
+ uses `enum` or `const`.
177
+
178
+ Regular-expression constraints on header names are the exception. A
179
+ `patternProperties` key and a `propertyNames` `pattern` are regular expressions
180
+ matched against the already-lowercased header names, and Fastify cannot safely
181
+ rewrite a regular expression. Author them to match lowercase (for example
182
+ `^x-debug-.*$`, not `^X-Debug-.*$`) or make them case-insensitive. A pattern
183
+ written in canonical case will not match, and the assertion it guards will not
184
+ apply.
185
+
170
186
  Example:
171
187
  ```js
172
188
  const bodyJsonSchema = {
@@ -639,6 +655,23 @@ an application.
639
655
  > failure by rejecting (throwing), and it cannot coerce the request part through
640
656
  > a resolved `value`.
641
657
 
658
+ ##### `headers` and the `{ value }` result
659
+
660
+ For the `headers` part specifically, the synchronous success `value` is applied
661
+ through the additive [`request.headers`](./Request.md#headers) setter. That
662
+ setter *adds or overrides* headers on top of the raw request headers; it does
663
+ **not** replace them. Raw request headers remain separately available as
664
+ `request.raw.headers`, and any incoming header that is not present in the
665
+ returned `value` is still visible on `request.headers`.
666
+
667
+ Consequently, a synchronous custom `headers` validator cannot remove a header by
668
+ simply omitting it from `value`. The same applies to the default Ajv validator:
669
+ `request.headers` is the incoming request's headers (plus any additive values)
670
+ and is not a sanitized, authoritative view. If your application needs a
671
+ sanitized or allow-listed header view — for example to drive an authorization
672
+ decision — build and consume that view explicitly from the validated data rather
673
+ than re-reading `request.headers`.
674
+
642
675
  ##### .statusCode property
643
676
 
644
677
  All validation errors have a `.statusCode` property set to `400`, ensuring the
@@ -766,7 +799,7 @@ For example:
766
799
  const schema = {
767
800
  response: {
768
801
  200: {
769
- description: 'Response schema that support different content types'
802
+ description: 'Response schema that support different content types',
770
803
  content: {
771
804
  'application/json': {
772
805
  schema: {
@@ -818,6 +851,15 @@ const schema = {
818
851
  fastify.post('/url', { schema }, handler)
819
852
  ```
820
853
 
854
+ > When the route declares a per-content-type response schema through `content`,
855
+ > Fastify matches the response `Content-Type` against the declared keys and falls
856
+ > back to `*/*` (if present). If the response `Content-Type` is not declared and
857
+ > there is no `*/*` key, serialization **fails closed**: Fastify throws
858
+ > `FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN` and replies with a `500` error,
859
+ > instead of silently serializing the payload with `JSON.stringify` (which would
860
+ > bypass the response schema). Every `Content-Type` a route may respond with must
861
+ > be declared, or the route must define a `*/*` catch-all.
862
+
821
863
  #### Serializer Compiler
822
864
  <a id="schema-serializer"></a>
823
865
 
@@ -898,6 +940,11 @@ message has to be rebuilt from the raw validation result:
898
940
  - `validationContext` is the part of the request that failed validation
899
941
  (`body`, `params`, `querystring` or `headers`).
900
942
  - `code` is `FST_ERR_VALIDATION` and `statusCode` is `400`.
943
+ - When the validator reports a list of errors (as Ajv does) and the default
944
+ [`schemaErrorFormatter`](#schemaerrorformatter) is used, the error is an
945
+ instance of [`FST_ERR_VALIDATION`](./Errors.md#fst_err_validation) without a
946
+ [stack trace](./Errors.md#errors-in-input-data). Errors returned by the
947
+ validator itself, or by a custom formatter, are used as they are.
901
948
 
902
949
  ```js
903
950
  const fastify = Fastify()
@@ -10,6 +10,7 @@
10
10
  - [Fastify Security Codes](#fastify-security-codes)
11
11
  - [FSTSEC001](#FSTSEC001)
12
12
  - [FSTSEC002](#FSTSEC002)
13
+ - [FSTSEC003](#FSTSEC003)
13
14
  - [Fastify Deprecation Codes](#fastify-deprecation-codes)
14
15
 
15
16
  ## Warnings
@@ -51,6 +52,7 @@ Disabling warnings is not recommended and may cause unexpected behavior.
51
52
  | ---- | ----------- | ------------ | ---------- |
52
53
  | <a id="FSTSEC001">FSTSEC001</a> | A `RegExp` Content-Type is used that may be vulnerable to a CORS bypass, because it does not anchor the essence MIME type. | Start the `RegExp` with `^` or include `;?` so the essence MIME type is detected correctly. | [#4450](https://github.com/fastify/fastify/pull/4450) |
53
54
  | <a id="FSTSEC002">FSTSEC002</a> | A headers schema references an external `$ref` (a schema registered with `addSchema`) that is not reached by header case normalization. Header names in the referenced schema keep their original case and do not match the lowercased request headers, so case-insensitive assertions such as `required` and `dependencies` may not apply. | Inline the header schema instead of referencing it with an external `$ref`. | - |
55
+ | <a id="FSTSEC003">FSTSEC003</a> | A headers schema uses a `$ref` inside `propertyNames` that is not reached by header case normalization. Header names held in the referenced schema keep their original case and do not match the lowercased request headers, so a case-insensitive deny-list or allow-list on header names may not apply. | Inline the `propertyNames` constraint instead of referencing it with a `$ref`. | - |
54
56
 
55
57
  ### Fastify Deprecation Codes
56
58