fastify 6.0.0-alpha.5 → 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.
- package/README.md +1 -0
- package/build/build-validation.js +2 -0
- package/docs/Guides/Ecosystem.md +4 -0
- package/docs/Guides/Migration-Guide-V5.md +2 -2
- package/docs/Guides/Serverless.md +33 -10
- package/docs/Reference/Errors.md +13 -0
- package/docs/Reference/Hooks.md +13 -0
- package/docs/Reference/Reply.md +786 -697
- package/docs/Reference/Request.md +303 -107
- package/docs/Reference/Server.md +39 -2
- package/docs/Reference/Validation-and-Serialization.md +15 -1
- package/fastify.d.ts +1 -0
- package/fastify.js +35 -1
- package/lib/config-validator.js +102 -73
- package/lib/content-type-parser.js +14 -2
- package/lib/context.js +2 -1
- package/lib/decorate.js +4 -3
- package/lib/error-handler.js +21 -4
- package/lib/error-status.js +4 -2
- package/lib/errors.js +15 -9
- package/lib/reply.js +12 -11
- package/lib/request.js +3 -2
- package/lib/route.js +34 -5
- package/lib/schemas.js +44 -32
- package/package.json +8 -3
- package/test/close-disposable.test.js +154 -0
- package/test/constrained-routes.test.js +4 -2
- package/test/content-parser.test.js +39 -0
- package/test/decorator.test.js +29 -0
- package/test/diagnostics-channel/error-status.test.js +35 -2
- package/test/handler-timeout.test.js +224 -0
- package/test/internals/all.test.js +5 -0
- package/test/internals/errors.test.js +18 -9
- package/test/internals/initial-config.test.js +2 -0
- package/test/internals/server.test.js +6 -4
- package/test/reply-error.test.js +82 -0
- package/test/reply-trailers.test.js +159 -1
- package/test/router-compile.test.js +241 -0
- package/test/schema-serialization.test.js +120 -7
- package/test/types/fastify.tst.ts +4 -0
- package/test/types/instance.tst.ts +1 -1
- package/test/types/route.tst.ts +16 -0
- package/test/types/using.tst.ts +20 -0
- package/test/validation-error-handling.test.js +21 -1
- package/types/instance.d.ts +5 -1
- package/types/route.d.ts +1 -0
|
@@ -1,42 +1,112 @@
|
|
|
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
|
|
8
|
-
|
|
9
|
-
- `
|
|
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
|
|
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.
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
36
|
-
|
|
37
|
-
- `
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
- `port` - The port parsed from `request.host`.
|
|
56
|
+
- `protocol` - The protocol of the incoming request (`https` or `http`).
|
|
57
|
+
- `method` - The method of the incoming request.
|
|
58
|
+
- `url` - The URL of the incoming request.
|
|
59
|
+
- `originalUrl` - The original URL of the incoming request.
|
|
60
|
+
- `mediaType` - The media type extracted from `Content-Type` header.
|
|
61
|
+
- `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
|
|
62
|
+
- `socket` - The underlying connection of the incoming request.
|
|
63
|
+
- `signal` - An `AbortSignal` that aborts on handler timeout or client
|
|
64
|
+
disconnect.
|
|
65
|
+
- `routeOptions` - The route [`option`](./Routes.md#routes-options) object.
|
|
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.
|
|
69
|
+
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
|
|
70
|
+
Returns a validation function for the specified schema or HTTP part, if
|
|
71
|
+
set or cached.
|
|
72
|
+
- [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
|
|
73
|
+
Compiles the specified schema and returns a validation function using the
|
|
74
|
+
default (or customized) `ValidationCompiler`. The optional `httpPart` is
|
|
75
|
+
forwarded to the `ValidationCompiler` if provided, defaults to `null`.
|
|
76
|
+
- [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
|
|
77
|
+
Validates the input using the specified schema or HTTP part and returns
|
|
78
|
+
`true` if the input is valid, `false` otherwise. If `httpPart` is provided,
|
|
79
|
+
the function uses the validator for that HTTP part. Defaults to `null`.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
fastify.post('/:params', options, function (request, reply) {
|
|
83
|
+
console.log(request.body)
|
|
84
|
+
console.log(request.query)
|
|
85
|
+
console.log(request.params)
|
|
86
|
+
console.log(request.headers)
|
|
87
|
+
console.log(request.raw)
|
|
88
|
+
console.log(request.server)
|
|
89
|
+
console.log(request.id)
|
|
90
|
+
console.log(request.ip)
|
|
91
|
+
console.log(request.ips)
|
|
92
|
+
console.log(request.host)
|
|
93
|
+
console.log(request.hostname)
|
|
94
|
+
console.log(request.port)
|
|
95
|
+
console.log(request.protocol)
|
|
96
|
+
console.log(request.url)
|
|
97
|
+
console.log(request.routeOptions.method)
|
|
98
|
+
console.log(request.routeOptions.bodyLimit)
|
|
99
|
+
console.log(request.routeOptions.handlerTimeout)
|
|
100
|
+
console.log(request.routeOptions.url)
|
|
101
|
+
console.log(request.routeOptions.attachValidation)
|
|
102
|
+
console.log(request.routeOptions.logLevel)
|
|
103
|
+
console.log(request.routeOptions.version)
|
|
104
|
+
console.log(request.routeOptions.exposeHeadRoute)
|
|
105
|
+
console.log(request.routeOptions.prefixTrailingSlash)
|
|
106
|
+
console.log(request.routeOptions.config)
|
|
107
|
+
request.log.info('some info')
|
|
108
|
+
})
|
|
109
|
+
```
|
|
40
110
|
|
|
41
111
|
> ⚠️ Security:
|
|
42
112
|
> `request.params`, `request.query`, `request.headers`, and `request.body`
|
|
@@ -55,51 +125,32 @@ Request is a core Fastify object containing the following fields:
|
|
|
55
125
|
> they must be validated explicitly (for example: trusted proxy
|
|
56
126
|
> configuration, allow-lists, strict parsing, and normalization).
|
|
57
127
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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.
|
|
75
|
-
- `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.
|
|
90
|
-
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
|
|
91
|
-
Returns a validation function for the specified schema or HTTP part, if
|
|
92
|
-
set or cached.
|
|
93
|
-
- [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
|
|
94
|
-
Compiles the specified schema and returns a validation function using the
|
|
95
|
-
default (or customized) `ValidationCompiler`. The optional `httpPart` is
|
|
96
|
-
forwarded to the `ValidationCompiler` if provided, defaults to `null`.
|
|
97
|
-
- [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
|
|
98
|
-
Validates the input using the specified schema or HTTP part and returns
|
|
99
|
-
`true` if the input is valid, `false` otherwise. If `httpPart` is provided,
|
|
100
|
-
the function uses the validator for that HTTP part. Defaults to `null`.
|
|
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
|
|
101
141
|
|
|
102
|
-
|
|
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
|
|
103
154
|
|
|
104
155
|
The `request.headers` is a getter that returns an object with the headers of the
|
|
105
156
|
incoming request. Set custom headers as follows:
|
|
@@ -112,7 +163,7 @@ request.headers = {
|
|
|
112
163
|
```
|
|
113
164
|
|
|
114
165
|
This operation adds new values to the request headers, accessible via
|
|
115
|
-
`request.headers.
|
|
166
|
+
`request.headers.foo`. Standard request headers remain accessible via
|
|
116
167
|
`request.raw.headers`.
|
|
117
168
|
|
|
118
169
|
For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added
|
|
@@ -130,41 +181,186 @@ to headers on `not found` routes.
|
|
|
130
181
|
> your application needs an allow-listed header subset, build and consume it
|
|
131
182
|
> explicitly from the validated data or from `request.raw.headers`.
|
|
132
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
|
+
|
|
133
308
|
```js
|
|
134
|
-
fastify.post('
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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 })
|
|
160
338
|
})
|
|
161
339
|
```
|
|
162
|
-
|
|
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)
|
|
163
359
|
<a id="getvalidationfunction"></a>
|
|
164
360
|
|
|
165
361
|
By calling this function with a provided `schema` or `httpPart`, it returns a
|
|
166
362
|
`validation` function to validate diverse inputs. It returns `undefined` if no
|
|
167
|
-
|
|
363
|
+
validation function is found using the provided inputs.
|
|
168
364
|
|
|
169
365
|
This function has an `errors` property. Errors encountered during the last
|
|
170
366
|
validation are assigned to `errors`.
|
|
@@ -190,10 +386,10 @@ console.log(validate({ foo: 0.5 })) // false
|
|
|
190
386
|
console.log(validate.errors) // validation errors
|
|
191
387
|
```
|
|
192
388
|
|
|
193
|
-
See [.compileValidationSchema(schema, [
|
|
389
|
+
See [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema)
|
|
194
390
|
for more information on compiling validation schemas.
|
|
195
391
|
|
|
196
|
-
|
|
392
|
+
##### .compileValidationSchema(schema, [httpPart])
|
|
197
393
|
<a id="compilevalidationschema"></a>
|
|
198
394
|
|
|
199
395
|
This function compiles a validation schema and returns a function to validate data.
|
|
@@ -231,8 +427,8 @@ const validate = request
|
|
|
231
427
|
type: 'string'
|
|
232
428
|
}
|
|
233
429
|
}
|
|
234
|
-
},
|
|
235
|
-
console.log(validate({
|
|
430
|
+
}, 'body')
|
|
431
|
+
console.log(validate({ foo: {} })) // false
|
|
236
432
|
console.log(validate.errors) // validation errors
|
|
237
433
|
```
|
|
238
434
|
|
|
@@ -280,7 +476,7 @@ const newValidate = request.compileValidationSchema(newSchema)
|
|
|
280
476
|
console.log(newValidate === validate) // false
|
|
281
477
|
```
|
|
282
478
|
|
|
283
|
-
|
|
479
|
+
##### .validateInput(data, [schema | httpPart], [httpPart])
|
|
284
480
|
<a id="validate"></a>
|
|
285
481
|
|
|
286
482
|
This function validates the input based on the provided schema or HTTP part. If
|
|
@@ -318,5 +514,5 @@ request
|
|
|
318
514
|
.validateInput({ hello: 'world'}, 'query') // false
|
|
319
515
|
```
|
|
320
516
|
|
|
321
|
-
See [.compileValidationSchema(schema, [
|
|
517
|
+
See [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema)
|
|
322
518
|
for more information on compiling validation schemas.
|
package/docs/Reference/Server.md
CHANGED
|
@@ -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)
|
|
@@ -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
|
-
|
|
1048
|
-
against
|
|
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
|
|
1049
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
|
|
@@ -799,7 +799,7 @@ For example:
|
|
|
799
799
|
const schema = {
|
|
800
800
|
response: {
|
|
801
801
|
200: {
|
|
802
|
-
description: 'Response schema that support different content types'
|
|
802
|
+
description: 'Response schema that support different content types',
|
|
803
803
|
content: {
|
|
804
804
|
'application/json': {
|
|
805
805
|
schema: {
|
|
@@ -851,6 +851,15 @@ const schema = {
|
|
|
851
851
|
fastify.post('/url', { schema }, handler)
|
|
852
852
|
```
|
|
853
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
|
+
|
|
854
863
|
#### Serializer Compiler
|
|
855
864
|
<a id="schema-serializer"></a>
|
|
856
865
|
|
|
@@ -931,6 +940,11 @@ message has to be rebuilt from the raw validation result:
|
|
|
931
940
|
- `validationContext` is the part of the request that failed validation
|
|
932
941
|
(`body`, `params`, `querystring` or `headers`).
|
|
933
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.
|
|
934
948
|
|
|
935
949
|
```js
|
|
936
950
|
const fastify = Fastify()
|
package/fastify.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ declare namespace fastify {
|
|
|
96
96
|
type TrustProxyFunction = (address: string, hop: number) => boolean
|
|
97
97
|
|
|
98
98
|
export type FastifyRouterOptions<RawServer extends RawServerBase> = Omit<FindMyWayConfigForServer<RawServer>, 'defaultRoute' | 'onBadUrl' | 'onMaxParamLength' | 'querystringParser' | 'constraints'> & {
|
|
99
|
+
compile?: boolean,
|
|
99
100
|
constraints?: {
|
|
100
101
|
[name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>,
|
|
101
102
|
},
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '6.0.0-alpha.
|
|
3
|
+
const VERSION = '6.0.0-alpha.6'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -83,6 +83,23 @@ const { buildErrorHandler } = require('./lib/error-handler.js')
|
|
|
83
83
|
|
|
84
84
|
const initChannel = diagnostics.channel('fastify.initialization')
|
|
85
85
|
|
|
86
|
+
function asyncDisposableHook (disposable) {
|
|
87
|
+
return function (instance, done) {
|
|
88
|
+
disposable[Symbol.asyncDispose]().then(() => done(), done)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function disposableHook (disposable) {
|
|
93
|
+
return function (instance, done) {
|
|
94
|
+
try {
|
|
95
|
+
disposable[Symbol.dispose]()
|
|
96
|
+
done()
|
|
97
|
+
} catch (err) {
|
|
98
|
+
done(err)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
86
103
|
/**
|
|
87
104
|
* @param {import('./fastify.js').FastifyServerOptions} serverOptions
|
|
88
105
|
*/
|
|
@@ -381,6 +398,13 @@ function fastify (serverOptions) {
|
|
|
381
398
|
|
|
382
399
|
// cache the closing value, since we are checking it in an hot path
|
|
383
400
|
avvio.once('preReady', () => {
|
|
401
|
+
// All the routes are registered at this point. Routes added or removed
|
|
402
|
+
// afterwards make find-my-way compile the changed trees again lazily.
|
|
403
|
+
if (options.routerOptions.compile === true) {
|
|
404
|
+
router.compileRoutes()
|
|
405
|
+
fourOhFour.router.compile()
|
|
406
|
+
}
|
|
407
|
+
|
|
384
408
|
fastify.onClose((instance, done) => {
|
|
385
409
|
fastify[kState].closing = true
|
|
386
410
|
router.closeRoutes()
|
|
@@ -598,6 +622,16 @@ function fastify (serverOptions) {
|
|
|
598
622
|
}
|
|
599
623
|
}
|
|
600
624
|
|
|
625
|
+
if (name === 'onClose' && typeof fn !== 'function') {
|
|
626
|
+
if (typeof fn[Symbol.asyncDispose] === 'function') {
|
|
627
|
+
fn = asyncDisposableHook(fn)
|
|
628
|
+
} else if (typeof fn[Symbol.dispose] === 'function') {
|
|
629
|
+
fn = disposableHook(fn)
|
|
630
|
+
} else {
|
|
631
|
+
throw new errorCodes.FST_ERR_HOOK_INVALID_HANDLER(name, Object.prototype.toString.call(fn))
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
601
635
|
if (name === 'onClose') {
|
|
602
636
|
this.onClose(fn.bind(this))
|
|
603
637
|
} else if (name === 'onReady' || name === 'onListen' || name === 'onRoute' || name === 'preClose') {
|