fastify 4.20.0 → 4.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/docs/Reference/Server.md +195 -181
- package/docs/Reference/TypeScript.md +1 -1
- package/fastify.js +1 -1
- package/lib/errors.js +1 -1
- package/lib/reply.js +16 -4
- package/package.json +2 -5
- package/test/async-await.test.js +1 -1
- package/test/internals/errors.test.js +2 -2
- package/test/internals/reply.test.js +33 -2
- package/test/serial/logger.0.test.js +6 -1
- package/test/stream.test.js +4 -4
- package/test/types/reply.test-d.ts +25 -0
- package/test/types/type-provider.test-d.ts +56 -0
- package/types/reply.d.ts +8 -6
- package/types/type-provider.d.ts +2 -1
- package/types/utils.d.ts +9 -0
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ CI](https://github.com/fastify/fastify/workflows/package-manager-ci/badge.svg?br
|
|
|
15
15
|
[](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
|
17
17
|
[](https://standardjs.com/)
|
|
18
|
+
[](https://bestpractices.coreinfrastructure.org/projects/7585)
|
|
18
19
|
|
|
19
20
|
</div>
|
|
20
21
|
|
|
@@ -48,7 +49,7 @@ The `main` branch refers to the Fastify `v4` release. Check out the
|
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
### Table of Contents
|
|
52
|
+
### Table of Contents
|
|
52
53
|
|
|
53
54
|
- [Quick start](#quick-start)
|
|
54
55
|
- [Install](#install)
|
package/docs/Reference/Server.md
CHANGED
|
@@ -98,6 +98,8 @@ describes the properties available in that options object.
|
|
|
98
98
|
### `http`
|
|
99
99
|
<a id="factory-http"></a>
|
|
100
100
|
|
|
101
|
+
+ Default: `null`
|
|
102
|
+
|
|
101
103
|
An object used to configure the server's listening socket. The options
|
|
102
104
|
are the same as the Node.js core [`createServer`
|
|
103
105
|
method](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_http_createserver_options_requestlistener).
|
|
@@ -105,20 +107,20 @@ method](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_http_create
|
|
|
105
107
|
This option is ignored if options [`http2`](#factory-http2) or
|
|
106
108
|
[`https`](#factory-https) are set.
|
|
107
109
|
|
|
108
|
-
+ Default: `null`
|
|
109
|
-
|
|
110
110
|
### `http2`
|
|
111
111
|
<a id="factory-http2"></a>
|
|
112
112
|
|
|
113
|
+
+ Default: `false`
|
|
114
|
+
|
|
113
115
|
If `true` Node.js core's
|
|
114
116
|
[HTTP/2](https://nodejs.org/dist/latest-v14.x/docs/api/http2.html) module is
|
|
115
117
|
used for binding the socket.
|
|
116
118
|
|
|
117
|
-
+ Default: `false`
|
|
118
|
-
|
|
119
119
|
### `https`
|
|
120
120
|
<a id="factory-https"></a>
|
|
121
121
|
|
|
122
|
+
+ Default: `null`
|
|
123
|
+
|
|
122
124
|
An object used to configure the server's listening socket for TLS. The options
|
|
123
125
|
are the same as the Node.js core [`createServer`
|
|
124
126
|
method](https://nodejs.org/dist/latest-v14.x/docs/api/https.html#https_https_createserver_options_requestlistener).
|
|
@@ -126,96 +128,100 @@ When this property is `null`, the socket will not be configured for TLS.
|
|
|
126
128
|
|
|
127
129
|
This option also applies when the [`http2`](#factory-http2) option is set.
|
|
128
130
|
|
|
129
|
-
+ Default: `null`
|
|
130
|
-
|
|
131
131
|
### `connectionTimeout`
|
|
132
132
|
<a id="factory-connection-timeout"></a>
|
|
133
133
|
|
|
134
|
+
+ Default: `0` (no timeout)
|
|
135
|
+
|
|
134
136
|
Defines the server timeout in milliseconds. See documentation for
|
|
135
137
|
[`server.timeout`
|
|
136
138
|
property](https://nodejs.org/api/http.html#http_server_timeout) to understand
|
|
137
|
-
the effect of this option.
|
|
138
|
-
is ignored.
|
|
139
|
+
the effect of this option.
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
When `serverFactory` option is specified this option is ignored.
|
|
141
142
|
|
|
142
143
|
### `keepAliveTimeout`
|
|
143
144
|
<a id="factory-keep-alive-timeout"></a>
|
|
144
145
|
|
|
146
|
+
+ Default: `72000` (72 seconds)
|
|
147
|
+
|
|
145
148
|
Defines the server keep-alive timeout in milliseconds. See documentation for
|
|
146
149
|
[`server.keepAliveTimeout`
|
|
147
150
|
property](https://nodejs.org/api/http.html#http_server_keepalivetimeout) to
|
|
148
151
|
understand the effect of this option. This option only applies when HTTP/1 is in
|
|
149
|
-
use.
|
|
152
|
+
use.
|
|
150
153
|
|
|
151
|
-
|
|
154
|
+
When `serverFactory` option is specified this option is ignored.
|
|
152
155
|
|
|
153
156
|
### `forceCloseConnections`
|
|
154
157
|
<a id="forcecloseconnections"></a>
|
|
155
158
|
|
|
159
|
+
+ Default: `"idle"` if the HTTP server allows it, `false` otherwise
|
|
160
|
+
|
|
156
161
|
When set to `true`, upon [`close`](#close) the server will iterate the current
|
|
157
162
|
persistent connections and [destroy their
|
|
158
163
|
sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror).
|
|
159
164
|
|
|
160
|
-
>
|
|
161
|
-
>
|
|
165
|
+
> **Warning**
|
|
166
|
+
> Connections are not inspected to determine if requests have
|
|
167
|
+
> been completed.
|
|
162
168
|
|
|
163
169
|
Fastify will prefer the HTTP server's
|
|
164
170
|
[`closeAllConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseallconnections)
|
|
165
|
-
method if supported, otherwise it will use internal connection tracking.
|
|
171
|
+
method if supported, otherwise, it will use internal connection tracking.
|
|
166
172
|
|
|
167
173
|
When set to `"idle"`, upon [`close`](#close) the server will iterate the current
|
|
168
174
|
persistent connections which are not sending a request or waiting for a response
|
|
169
|
-
and destroy their sockets. The value is supported
|
|
175
|
+
and destroy their sockets. The value is only supported if the HTTP server
|
|
170
176
|
supports the
|
|
171
177
|
[`closeIdleConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseidleconnections)
|
|
172
178
|
method, otherwise attempting to set it will throw an exception.
|
|
173
179
|
|
|
174
|
-
+ Default: `"idle"` if the HTTP server allows it, `false` otherwise
|
|
175
|
-
|
|
176
180
|
### `maxRequestsPerSocket`
|
|
177
181
|
<a id="factory-max-requests-per-socket"></a>
|
|
178
182
|
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
+ Default: `0` (no limit)
|
|
184
|
+
|
|
185
|
+
Defines the maximum number of requests a socket can handle before closing keep
|
|
186
|
+
alive connection. See [`server.maxRequestsPerSocket`
|
|
181
187
|
property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_maxrequestspersocket)
|
|
182
188
|
to understand the effect of this option. This option only applies when HTTP/1.1
|
|
183
189
|
is in use. Also, when `serverFactory` option is specified, this option is
|
|
184
190
|
ignored.
|
|
185
|
-
> At the time of this writing, only node version greater or equal to 16.10.0
|
|
186
|
-
> support this option. Check the Node.js documentation for availability in the
|
|
187
|
-
> version you are running.
|
|
188
191
|
|
|
189
|
-
|
|
192
|
+
> **Note**
|
|
193
|
+
> At the time of writing, only node >= v16.10.0 supports this option.
|
|
190
194
|
|
|
191
195
|
### `requestTimeout`
|
|
192
196
|
<a id="factory-request-timeout"></a>
|
|
193
197
|
|
|
198
|
+
+ Default: `0` (no limit)
|
|
199
|
+
|
|
194
200
|
Defines the maximum number of milliseconds for receiving the entire request from
|
|
195
|
-
the client. [`server.requestTimeout`
|
|
201
|
+
the client. See [`server.requestTimeout`
|
|
196
202
|
property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
|
|
197
|
-
to understand the effect of this option.
|
|
198
|
-
specified, this option is ignored. It must be set to a non-zero value (e.g. 120
|
|
199
|
-
seconds) to protect against potential Denial-of-Service attacks in case the
|
|
200
|
-
server is deployed without a reverse proxy in front.
|
|
201
|
-
> At the time of this writing, only node version greater or equal to 14.11.0
|
|
202
|
-
> support this option. Check the Node.js documentation for availability in the
|
|
203
|
-
> version you are running.
|
|
203
|
+
to understand the effect of this option.
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
When `serverFactory` option is specified, this option is ignored.
|
|
206
|
+
It must be set to a non-zero value (e.g. 120 seconds) to protect against potential
|
|
207
|
+
Denial-of-Service attacks in case the server is deployed without a reverse proxy
|
|
208
|
+
in front.
|
|
209
|
+
|
|
210
|
+
> **Note**
|
|
211
|
+
> At the time of writing, only node >= v14.11.0 supports this option
|
|
206
212
|
|
|
207
213
|
### `ignoreTrailingSlash`
|
|
208
214
|
<a id="factory-ignore-slash"></a>
|
|
209
215
|
|
|
216
|
+
+ Default: `false`
|
|
217
|
+
|
|
210
218
|
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) to handle
|
|
211
|
-
routing. By default, Fastify
|
|
212
|
-
Paths like `/foo` and `/foo/`
|
|
219
|
+
routing. By default, Fastify will take into account the trailing slashes.
|
|
220
|
+
Paths like `/foo` and `/foo/` are treated as different paths. If you want to
|
|
213
221
|
change this, set this flag to `true`. That way, both `/foo` and `/foo/` will
|
|
214
222
|
point to the same route. This option applies to *all* route registrations for
|
|
215
223
|
the resulting server instance.
|
|
216
224
|
|
|
217
|
-
+ Default: `false`
|
|
218
|
-
|
|
219
225
|
```js
|
|
220
226
|
const fastify = require('fastify')({
|
|
221
227
|
ignoreTrailingSlash: true
|
|
@@ -235,17 +241,17 @@ fastify.get('/bar', function (req, reply) {
|
|
|
235
241
|
### `ignoreDuplicateSlashes`
|
|
236
242
|
<a id="factory-ignore-duplicate-slashes"></a>
|
|
237
243
|
|
|
244
|
+
+ Default: `false`
|
|
245
|
+
|
|
238
246
|
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) to handle
|
|
239
247
|
routing. You can use `ignoreDuplicateSlashes` option to remove duplicate slashes
|
|
240
|
-
from the path. It removes duplicate slashes in the route path and
|
|
248
|
+
from the path. It removes duplicate slashes in the route path and the request
|
|
241
249
|
URL. This option applies to *all* route registrations for the resulting server
|
|
242
250
|
instance.
|
|
243
251
|
|
|
244
|
-
|
|
245
|
-
to true
|
|
246
|
-
meaning
|
|
247
|
-
|
|
248
|
-
+ Default: `false`
|
|
252
|
+
When `ignoreTrailingSlash` and `ignoreDuplicateSlashes` are both set
|
|
253
|
+
to `true` Fastify will remove duplicate slashes, and then trailing slashes,
|
|
254
|
+
meaning `//a//b//c//` will be converted to `/a/b/c`.
|
|
249
255
|
|
|
250
256
|
```js
|
|
251
257
|
const fastify = require('fastify')({
|
|
@@ -263,46 +269,45 @@ fastify.get('///foo//bar//', function (req, reply) {
|
|
|
263
269
|
|
|
264
270
|
You can set a custom length for parameters in parametric (standard, regex, and
|
|
265
271
|
multi) routes by using `maxParamLength` option; the default value is 100
|
|
266
|
-
characters.
|
|
272
|
+
characters. If the maximum length limit is reached, the not found route will
|
|
273
|
+
be invoked.
|
|
267
274
|
|
|
268
275
|
This can be useful especially if you have a regex-based route, protecting you
|
|
269
|
-
against [
|
|
276
|
+
against [ReDoS
|
|
270
277
|
attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS).
|
|
271
278
|
|
|
272
|
-
*If the maximum length limit is reached, the not found route will be invoked.*
|
|
273
|
-
|
|
274
279
|
### `bodyLimit`
|
|
275
280
|
<a id="factory-body-limit"></a>
|
|
276
281
|
|
|
277
|
-
Defines the maximum payload, in bytes, the server is allowed to accept.
|
|
278
|
-
|
|
279
282
|
+ Default: `1048576` (1MiB)
|
|
280
283
|
|
|
284
|
+
Defines the maximum payload, in bytes, the server is allowed to accept.
|
|
285
|
+
|
|
281
286
|
### `onProtoPoisoning`
|
|
282
287
|
<a id="factory-on-proto-poisoning"></a>
|
|
283
288
|
|
|
289
|
+
+ Default: `'error'`
|
|
290
|
+
|
|
284
291
|
Defines what action the framework must take when parsing a JSON object with
|
|
285
292
|
`__proto__`. This functionality is provided by
|
|
286
293
|
[secure-json-parse](https://github.com/fastify/secure-json-parse). See
|
|
287
294
|
[Prototype Poisoning](../Guides/Prototype-Poisoning.md) for more details about
|
|
288
295
|
prototype poisoning attacks.
|
|
289
296
|
|
|
290
|
-
Possible values are `'error'`, `'remove'
|
|
291
|
-
|
|
292
|
-
+ Default: `'error'`
|
|
297
|
+
Possible values are `'error'`, `'remove'`, or `'ignore'`.
|
|
293
298
|
|
|
294
299
|
### `onConstructorPoisoning`
|
|
295
300
|
<a id="factory-on-constructor-poisoning"></a>
|
|
296
301
|
|
|
302
|
+
+ Default: `'error'`
|
|
303
|
+
|
|
297
304
|
Defines what action the framework must take when parsing a JSON object with
|
|
298
305
|
`constructor`. This functionality is provided by
|
|
299
306
|
[secure-json-parse](https://github.com/fastify/secure-json-parse). See
|
|
300
307
|
[Prototype Poisoning](../Guides/Prototype-Poisoning.md) for more details about
|
|
301
308
|
prototype poisoning attacks.
|
|
302
309
|
|
|
303
|
-
Possible values are `'error'`, `'remove'
|
|
304
|
-
|
|
305
|
-
+ Default: `'error'`
|
|
310
|
+
Possible values are `'error'`, `'remove'`, or `'ignore'`.
|
|
306
311
|
|
|
307
312
|
### `logger`
|
|
308
313
|
<a id="factory-logger"></a>
|
|
@@ -363,13 +368,18 @@ The possible values this property may have are:
|
|
|
363
368
|
### `disableRequestLogging`
|
|
364
369
|
<a id="factory-disable-request-logging"></a>
|
|
365
370
|
|
|
366
|
-
|
|
371
|
+
+ Default: `false`
|
|
372
|
+
|
|
373
|
+
When logging is enabled, Fastify will issue an `info` level log
|
|
367
374
|
message when a request is received and when the response for that request has
|
|
368
375
|
been sent. By setting this option to `true`, these log messages will be
|
|
369
376
|
disabled. This allows for more flexible request start and end logging by
|
|
370
377
|
attaching custom `onRequest` and `onResponse` hooks.
|
|
371
378
|
|
|
372
|
-
|
|
379
|
+
Please note that this option will also disable an error log written by the
|
|
380
|
+
default `onResponse` hook on reply callback errors. Other log messages
|
|
381
|
+
emitted by Fastify will stay enabled, like deprecation warnings and messages
|
|
382
|
+
emitted when requests are received while the server is closing.
|
|
373
383
|
|
|
374
384
|
```js
|
|
375
385
|
// Examples of hooks to replicate the disabled functionality.
|
|
@@ -384,11 +394,6 @@ fastify.addHook('onResponse', (req, reply, done) => {
|
|
|
384
394
|
})
|
|
385
395
|
```
|
|
386
396
|
|
|
387
|
-
Please note that this setting will also disable an error log written by the
|
|
388
|
-
default `onResponse` hook on reply callback errors. Other log messages
|
|
389
|
-
emitted by Fastify will stay enabled, like deprecation warnings and messages
|
|
390
|
-
emitted when requests are received while the server is closing.
|
|
391
|
-
|
|
392
397
|
### `serverFactory`
|
|
393
398
|
<a id="custom-http-server"></a>
|
|
394
399
|
|
|
@@ -428,13 +433,17 @@ enhance the server instance inside the `serverFactory` function before the
|
|
|
428
433
|
|
|
429
434
|
+ Default: `true`
|
|
430
435
|
|
|
431
|
-
|
|
436
|
+
By default, Fastify will automatically infer the root properties
|
|
432
437
|
of JSON Schemas if it does not find valid root properties according to the JSON
|
|
433
|
-
Schema spec. If you wish to implement your own schema validation compiler,
|
|
434
|
-
|
|
438
|
+
Schema spec. If you wish to implement your own schema validation compiler, to
|
|
439
|
+
parse schemas as JTD instead of JSON Schema for example, then you can explicitly
|
|
435
440
|
set this option to `false` to make sure the schemas you receive are unmodified
|
|
436
441
|
and are not being treated internally as JSON Schema.
|
|
437
442
|
|
|
443
|
+
Fastify does not throw on invalid schemas so if this option is set to `false`
|
|
444
|
+
in an existing project, check that none of your existing schemas become
|
|
445
|
+
invalid as a result, as they will be treated as catch-alls.
|
|
446
|
+
|
|
438
447
|
```js
|
|
439
448
|
const AjvJTD = require('ajv/dist/jtd'/* only valid for AJV v7+ */)
|
|
440
449
|
const ajv = new AjvJTD({
|
|
@@ -457,21 +466,23 @@ fastify.post('/', {
|
|
|
457
466
|
})
|
|
458
467
|
```
|
|
459
468
|
|
|
460
|
-
**Note: Fastify does not currently throw on invalid schemas, so if you turn this
|
|
461
|
-
off in an existing project, you need to be careful that none of your existing
|
|
462
|
-
schemas become invalid as a result, since they will be treated as a catch-all.**
|
|
463
|
-
|
|
464
469
|
### `caseSensitive`
|
|
465
470
|
<a id="factory-case-sensitive"></a>
|
|
466
471
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
472
|
+
+ Default: `true`
|
|
473
|
+
|
|
474
|
+
When `true` routes are registered as case-sensitive. That is, `/foo`
|
|
475
|
+
is not equal to `/Foo`.
|
|
476
|
+
When `false` then routes are case-insensitive.
|
|
477
|
+
|
|
478
|
+
Please note that setting this option to `false` goes against
|
|
479
|
+
[RFC3986](https://tools.ietf.org/html/rfc3986#section-6.2.2.1).
|
|
471
480
|
|
|
472
481
|
By setting `caseSensitive` to `false`, all paths will be matched as lowercase,
|
|
473
482
|
but the route parameters or wildcards will maintain their original letter
|
|
474
|
-
casing.
|
|
483
|
+
casing.
|
|
484
|
+
This option does not affect query strings, please refer to
|
|
485
|
+
[`querystringParser`](#querystringparser) to change their handling.
|
|
475
486
|
|
|
476
487
|
```js
|
|
477
488
|
fastify.get('/user/:username', (request, reply) => {
|
|
@@ -480,19 +491,13 @@ fastify.get('/user/:username', (request, reply) => {
|
|
|
480
491
|
})
|
|
481
492
|
```
|
|
482
493
|
|
|
483
|
-
Please note that setting this option to `false` goes against
|
|
484
|
-
[RFC3986](https://tools.ietf.org/html/rfc3986#section-6.2.2.1).
|
|
485
|
-
|
|
486
|
-
Also note, this setting will not affect query strings. If you want to change the
|
|
487
|
-
way query strings are handled take a look at
|
|
488
|
-
[`querystringParser`](#querystringparser).
|
|
489
|
-
|
|
490
|
-
|
|
491
494
|
### `allowUnsafeRegex`
|
|
492
495
|
<a id="factory-allow-unsafe-regex"></a>
|
|
493
496
|
|
|
494
|
-
|
|
495
|
-
|
|
497
|
+
+ Default `false`
|
|
498
|
+
|
|
499
|
+
Disabled by default, so routes only allow safe regular expressions. To use
|
|
500
|
+
unsafe expressions, set `allowUnsafeRegex` to `true`.
|
|
496
501
|
|
|
497
502
|
```js
|
|
498
503
|
fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => {
|
|
@@ -500,18 +505,14 @@ fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => {
|
|
|
500
505
|
})
|
|
501
506
|
```
|
|
502
507
|
|
|
503
|
-
Under the hood: [FindMyWay](https://github.com/delvedor/find-my-way) More info
|
|
504
|
-
about safe regexp: [Safe-regex2](https://www.npmjs.com/package/safe-regex2)
|
|
505
|
-
|
|
506
|
-
|
|
507
508
|
### `requestIdHeader`
|
|
508
509
|
<a id="factory-request-id-header"></a>
|
|
509
510
|
|
|
511
|
+
+ Default: `'request-id'`
|
|
512
|
+
|
|
510
513
|
The header name used to set the request-id. See [the
|
|
511
514
|
request-id](./Logging.md#logging-request-id) section.
|
|
512
|
-
Setting `requestIdHeader` to `false` will always use [genReqId](#genreqid)
|
|
513
|
-
|
|
514
|
-
+ Default: `'request-id'`
|
|
515
|
+
Setting `requestIdHeader` to `false` will always use [genReqId](#genreqid).
|
|
515
516
|
|
|
516
517
|
```js
|
|
517
518
|
const fastify = require('fastify')({
|
|
@@ -519,25 +520,31 @@ const fastify = require('fastify')({
|
|
|
519
520
|
//requestIdHeader: false, // -> always use genReqId
|
|
520
521
|
})
|
|
521
522
|
```
|
|
523
|
+
|
|
522
524
|
### `requestIdLogLabel`
|
|
523
525
|
<a id="factory-request-id-log-label"></a>
|
|
524
526
|
|
|
525
|
-
Defines the label used for the request identifier when logging the request.
|
|
526
|
-
|
|
527
527
|
+ Default: `'reqId'`
|
|
528
528
|
|
|
529
|
+
Defines the label used for the request identifier when logging the request.
|
|
530
|
+
|
|
529
531
|
### `genReqId`
|
|
530
532
|
<a id="factory-gen-request-id"></a>
|
|
531
533
|
|
|
532
|
-
Function for generating the request-id. It will receive the _raw_ incoming
|
|
533
|
-
request as a parameter. This function is expected to be error-free.
|
|
534
|
-
|
|
535
534
|
+ Default: `value of 'request-id' header if provided or monotonically increasing
|
|
536
535
|
integers`
|
|
537
536
|
|
|
537
|
+
Function for generating the request-id. It will receive the _raw_ incoming
|
|
538
|
+
request as a parameter. This function is expected to be error-free.
|
|
539
|
+
|
|
538
540
|
Especially in distributed systems, you may want to override the default ID
|
|
539
541
|
generation behavior as shown below. For generating `UUID`s you may want to check
|
|
540
|
-
out [hyperid](https://github.com/mcollina/hyperid)
|
|
542
|
+
out [hyperid](https://github.com/mcollina/hyperid).
|
|
543
|
+
|
|
544
|
+
> **Note**
|
|
545
|
+
> `genReqId` will be not called if the header set in
|
|
546
|
+
> <code>[requestIdHeader](#requestidheader)</code> is available (defaults to
|
|
547
|
+
> 'request-id').
|
|
541
548
|
|
|
542
549
|
```js
|
|
543
550
|
let i = 0
|
|
@@ -546,21 +553,9 @@ const fastify = require('fastify')({
|
|
|
546
553
|
})
|
|
547
554
|
```
|
|
548
555
|
|
|
549
|
-
**Note: genReqId will _not_ be called if the header set in
|
|
550
|
-
<code>[requestIdHeader](#requestidheader)</code> is available (defaults to
|
|
551
|
-
'request-id').**
|
|
552
|
-
|
|
553
556
|
### `trustProxy`
|
|
554
557
|
<a id="factory-trust-proxy"></a>
|
|
555
558
|
|
|
556
|
-
By enabling the `trustProxy` option, Fastify will know that it is sitting behind
|
|
557
|
-
a proxy and that the `X-Forwarded-*` header fields may be trusted, which
|
|
558
|
-
otherwise may be easily spoofed.
|
|
559
|
-
|
|
560
|
-
```js
|
|
561
|
-
const fastify = Fastify({ trustProxy: true })
|
|
562
|
-
```
|
|
563
|
-
|
|
564
559
|
+ Default: `false`
|
|
565
560
|
+ `true/false`: Trust all proxies (`true`) or do not trust any proxies
|
|
566
561
|
(`false`).
|
|
@@ -575,6 +570,14 @@ const fastify = Fastify({ trustProxy: true })
|
|
|
575
570
|
}
|
|
576
571
|
```
|
|
577
572
|
|
|
573
|
+
By enabling the `trustProxy` option, Fastify will know that it is sitting behind
|
|
574
|
+
a proxy and that the `X-Forwarded-*` header fields may be trusted, which
|
|
575
|
+
otherwise may be easily spoofed.
|
|
576
|
+
|
|
577
|
+
```js
|
|
578
|
+
const fastify = Fastify({ trustProxy: true })
|
|
579
|
+
```
|
|
580
|
+
|
|
578
581
|
For more examples, refer to the
|
|
579
582
|
[`proxy-addr`](https://www.npmjs.com/package/proxy-addr) package.
|
|
580
583
|
|
|
@@ -590,28 +593,32 @@ fastify.get('/', (request, reply) => {
|
|
|
590
593
|
})
|
|
591
594
|
```
|
|
592
595
|
|
|
593
|
-
**Note
|
|
594
|
-
|
|
595
|
-
derive
|
|
596
|
+
> **Note**
|
|
597
|
+
> If a request contains multiple `x-forwarded-host` or `x-forwarded-proto`
|
|
598
|
+
> headers, it is only the last one that is used to derive `request.hostname`
|
|
599
|
+
> and `request.protocol`.
|
|
596
600
|
|
|
597
601
|
### `pluginTimeout`
|
|
598
602
|
<a id="plugin-timeout"></a>
|
|
599
603
|
|
|
604
|
+
+ Default: `10000`
|
|
605
|
+
|
|
600
606
|
The maximum amount of time in *milliseconds* in which a plugin can load. If not,
|
|
601
607
|
[`ready`](#ready) will complete with an `Error` with code
|
|
602
608
|
`'ERR_AVVIO_PLUGIN_TIMEOUT'`. When set to `0`, disables this check. This
|
|
603
609
|
controls [avvio](https://www.npmjs.com/package/avvio) 's `timeout` parameter.
|
|
604
610
|
|
|
605
|
-
+ Default: `10000`
|
|
606
|
-
|
|
607
611
|
### `querystringParser`
|
|
608
612
|
<a id="factory-querystring-parser"></a>
|
|
609
613
|
|
|
610
614
|
The default query string parser that Fastify uses is the Node.js's core
|
|
611
615
|
`querystring` module.
|
|
612
616
|
|
|
613
|
-
You can
|
|
614
|
-
|
|
617
|
+
You can use this option to use a custom parser, such as
|
|
618
|
+
[`qs`](https://www.npmjs.com/package/qs).
|
|
619
|
+
|
|
620
|
+
If you only want the keys (and not the values) to be case insensitive we
|
|
621
|
+
recommend using a custom parser to convert only the keys to lowercase.
|
|
615
622
|
|
|
616
623
|
```js
|
|
617
624
|
const qs = require('qs')
|
|
@@ -620,7 +627,7 @@ const fastify = require('fastify')({
|
|
|
620
627
|
})
|
|
621
628
|
```
|
|
622
629
|
|
|
623
|
-
You can also use Fastify's default parser but change some handling
|
|
630
|
+
You can also use Fastify's default parser but change some handling behavior,
|
|
624
631
|
like the example below for case insensitive keys and values:
|
|
625
632
|
|
|
626
633
|
```js
|
|
@@ -630,24 +637,21 @@ const fastify = require('fastify')({
|
|
|
630
637
|
})
|
|
631
638
|
```
|
|
632
639
|
|
|
633
|
-
Note, if you only want the keys (and not the values) to be case insensitive we
|
|
634
|
-
recommend using a custom parser to convert only the keys to lowercase.
|
|
635
|
-
|
|
636
640
|
### `exposeHeadRoutes`
|
|
637
641
|
<a id="exposeHeadRoutes"></a>
|
|
638
642
|
|
|
643
|
+
+ Default: `true`
|
|
644
|
+
|
|
639
645
|
Automatically creates a sibling `HEAD` route for each `GET` route defined. If
|
|
640
646
|
you want a custom `HEAD` handler without disabling this option, make sure to
|
|
641
647
|
define it before the `GET` route.
|
|
642
648
|
|
|
643
|
-
+ Default: `true`
|
|
644
|
-
|
|
645
649
|
### `constraints`
|
|
646
650
|
<a id="constraints"></a>
|
|
647
651
|
|
|
648
|
-
Fastify's built
|
|
649
|
-
constraining routes by `version` or `host`. You
|
|
650
|
-
strategies, or override the built
|
|
652
|
+
Fastify's built-in route constraints are provided by `find-my-way`, which
|
|
653
|
+
allows constraining routes by `version` or `host`. You can add new constraint
|
|
654
|
+
strategies, or override the built-in strategies, by providing a `constraints`
|
|
651
655
|
object with strategies for `find-my-way`. You can find more information on
|
|
652
656
|
constraint strategies in the
|
|
653
657
|
[find-my-way](https://github.com/delvedor/find-my-way) documentation.
|
|
@@ -676,11 +680,11 @@ const fastify = require('fastify')({
|
|
|
676
680
|
### `return503OnClosing`
|
|
677
681
|
<a id="factory-return-503-on-closing"></a>
|
|
678
682
|
|
|
683
|
+
+ Default: `true`
|
|
684
|
+
|
|
679
685
|
Returns 503 after calling `close` server method. If `false`, the server routes
|
|
680
686
|
the incoming request as usual.
|
|
681
687
|
|
|
682
|
-
+ Default: `true`
|
|
683
|
-
|
|
684
688
|
### `ajv`
|
|
685
689
|
<a id="factory-ajv"></a>
|
|
686
690
|
|
|
@@ -709,7 +713,7 @@ const fastify = require('fastify')({
|
|
|
709
713
|
|
|
710
714
|
Customize the options of the default
|
|
711
715
|
[`fast-json-stringify`](https://github.com/fastify/fast-json-stringify#options)
|
|
712
|
-
instance that
|
|
716
|
+
instance that serializes the response's payload:
|
|
713
717
|
|
|
714
718
|
```js
|
|
715
719
|
const fastify = require('fastify')({
|
|
@@ -722,15 +726,17 @@ const fastify = require('fastify')({
|
|
|
722
726
|
### `http2SessionTimeout`
|
|
723
727
|
<a id="http2-session-timeout"></a>
|
|
724
728
|
|
|
729
|
+
+ Default: `72000`
|
|
730
|
+
|
|
725
731
|
Set a default
|
|
726
|
-
[timeout](https://nodejs.org/api/http2.html#
|
|
727
|
-
to every incoming HTTP/2 session. The session will be closed on
|
|
728
|
-
|
|
732
|
+
[timeout](https://nodejs.org/api/http2.html#http2sessionsettimeoutmsecs-callback)
|
|
733
|
+
to every incoming HTTP/2 session in milliseconds. The session will be closed on
|
|
734
|
+
the timeout.
|
|
729
735
|
|
|
730
|
-
|
|
736
|
+
This option is needed to offer a graceful "close" experience when using
|
|
731
737
|
HTTP/2. The low default has been chosen to mitigate denial of service attacks.
|
|
732
738
|
When the server is behind a load balancer or can scale automatically this value
|
|
733
|
-
can be increased to fit the use case. Node core defaults this to `0`.
|
|
739
|
+
can be increased to fit the use case. Node core defaults this to `0`.
|
|
734
740
|
|
|
735
741
|
### `frameworkErrors`
|
|
736
742
|
<a id="framework-errors"></a>
|
|
@@ -741,8 +747,8 @@ Fastify provides default error handlers for the most common use cases. It is
|
|
|
741
747
|
possible to override one or more of those handlers with custom code using this
|
|
742
748
|
option.
|
|
743
749
|
|
|
744
|
-
|
|
745
|
-
|
|
750
|
+
> **Note**
|
|
751
|
+
> Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at present.
|
|
746
752
|
|
|
747
753
|
```js
|
|
748
754
|
const fastify = require('fastify')({
|
|
@@ -794,10 +800,11 @@ function defaultClientErrorHandler (err, socket) {
|
|
|
794
800
|
}
|
|
795
801
|
```
|
|
796
802
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
803
|
+
> **Note**
|
|
804
|
+
> `clientErrorHandler` operates with raw sockets. The handler is expected to
|
|
805
|
+
> return a properly formed HTTP response that includes a status line, HTTP headers
|
|
806
|
+
> and a message body. Before attempting to write the socket, the handler should
|
|
807
|
+
> check if the socket is still writable as it may have already been destroyed.
|
|
801
808
|
|
|
802
809
|
```js
|
|
803
810
|
const fastify = require('fastify')({
|
|
@@ -826,9 +833,11 @@ const fastify = require('fastify')({
|
|
|
826
833
|
<a id="rewrite-url"></a>
|
|
827
834
|
|
|
828
835
|
Set a sync callback function that must return a string that allows rewriting
|
|
829
|
-
URLs.
|
|
836
|
+
URLs. This is useful when you are behind a proxy that changes the URL.
|
|
837
|
+
Rewriting a URL will modify the `url` property of the `req` object.
|
|
830
838
|
|
|
831
|
-
|
|
839
|
+
Note that `rewriteUrl` is called _before_ routing, it is not encapsulated and it
|
|
840
|
+
is an instance-wide configuration.
|
|
832
841
|
|
|
833
842
|
```js
|
|
834
843
|
// @param {object} req The raw Node.js HTTP request, not the `FastifyRequest` object.
|
|
@@ -844,9 +853,6 @@ function rewriteUrl (req) {
|
|
|
844
853
|
}
|
|
845
854
|
```
|
|
846
855
|
|
|
847
|
-
Note that `rewriteUrl` is called _before_ routing, it is not encapsulated and it
|
|
848
|
-
is an instance-wide configuration.
|
|
849
|
-
|
|
850
856
|
## Instance
|
|
851
857
|
|
|
852
858
|
### Server Methods
|
|
@@ -858,8 +864,9 @@ is an instance-wide configuration.
|
|
|
858
864
|
[server](https://nodejs.org/api/http.html#http_class_http_server) object as
|
|
859
865
|
returned by the [**`Fastify factory function`**](#factory).
|
|
860
866
|
|
|
861
|
-
>
|
|
862
|
-
>
|
|
867
|
+
> **Warning**
|
|
868
|
+
> If utilized improperly, certain Fastify features could be disrupted.
|
|
869
|
+
> It is recommended to only use it for attaching listeners.
|
|
863
870
|
|
|
864
871
|
#### after
|
|
865
872
|
<a id="after"></a>
|
|
@@ -1057,8 +1064,9 @@ Note that the array contains the `fastify.server.address()` too.
|
|
|
1057
1064
|
#### getDefaultRoute
|
|
1058
1065
|
<a id="getDefaultRoute"></a>
|
|
1059
1066
|
|
|
1060
|
-
**
|
|
1061
|
-
|
|
1067
|
+
> **Warning**
|
|
1068
|
+
> This method is deprecated and will be removed in the next Fastify
|
|
1069
|
+
> major version.
|
|
1062
1070
|
|
|
1063
1071
|
The `defaultRoute` handler handles requests that do not match any URL specified
|
|
1064
1072
|
by your Fastify application. This defaults to the 404 handler, but can be
|
|
@@ -1072,9 +1080,10 @@ const defaultRoute = fastify.getDefaultRoute()
|
|
|
1072
1080
|
#### setDefaultRoute
|
|
1073
1081
|
<a id="setDefaultRoute"></a>
|
|
1074
1082
|
|
|
1075
|
-
**
|
|
1076
|
-
|
|
1077
|
-
|
|
1083
|
+
> **Warning**
|
|
1084
|
+
> This method is deprecated and will be removed in the next Fastify
|
|
1085
|
+
> major version. Please, consider using `setNotFoundHandler` or a wildcard
|
|
1086
|
+
> matching route.
|
|
1078
1087
|
|
|
1079
1088
|
The default 404 handler, or one set using `setNotFoundHandler`, will
|
|
1080
1089
|
never trigger if the default route is overridden. This sets the handler for the
|
|
@@ -1117,9 +1126,9 @@ Method to add routes to the server, it also has shorthand functions, check
|
|
|
1117
1126
|
<a id="hasRoute"></a>
|
|
1118
1127
|
|
|
1119
1128
|
Method to check if a route is already registered to the internal router. It
|
|
1120
|
-
expects an object as payload. `url` and `method` are mandatory fields. It
|
|
1121
|
-
possible to also specify `constraints`. The method returns true if the
|
|
1122
|
-
registered
|
|
1129
|
+
expects an object as the payload. `url` and `method` are mandatory fields. It
|
|
1130
|
+
is possible to also specify `constraints`. The method returns `true` if the
|
|
1131
|
+
route is registered or `false` if not.
|
|
1123
1132
|
|
|
1124
1133
|
```js
|
|
1125
1134
|
const routeExists = fastify.hasRoute({
|
|
@@ -1220,11 +1229,12 @@ different ways to define a name (in order).
|
|
|
1220
1229
|
Newlines are replaced by ` -- `. This will help to identify the root cause when
|
|
1221
1230
|
you deal with many plugins.
|
|
1222
1231
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1232
|
+
> **Warning**
|
|
1233
|
+
> If you have to deal with nested plugins, the name differs with the usage of
|
|
1234
|
+
> the [fastify-plugin](https://github.com/fastify/fastify-plugin) because
|
|
1235
|
+
> no new scope is created and therefore we have no place to attach contextual
|
|
1236
|
+
> data. In that case, the plugin name will represent the boot order of all
|
|
1237
|
+
> involved plugins in the format of `fastify -> plugin-A -> plugin-B`.
|
|
1228
1238
|
|
|
1229
1239
|
#### hasPlugin
|
|
1230
1240
|
<a id="hasPlugin"></a>
|
|
@@ -1327,7 +1337,9 @@ Set the schema error formatter for all routes. See
|
|
|
1327
1337
|
|
|
1328
1338
|
Set the schema serializer compiler for all routes. See
|
|
1329
1339
|
[#schema-serializer](./Validation-and-Serialization.md#schema-serializer).
|
|
1330
|
-
|
|
1340
|
+
|
|
1341
|
+
> **Note**
|
|
1342
|
+
> [`setReplySerializer`](#set-reply-serializer) has priority if set!
|
|
1331
1343
|
|
|
1332
1344
|
#### validatorCompiler
|
|
1333
1345
|
<a id="validator-compiler"></a>
|
|
@@ -1362,9 +1374,7 @@ This property can be used to fully manage:
|
|
|
1362
1374
|
- `compilersFactory`: what module must compile the JSON schemas
|
|
1363
1375
|
|
|
1364
1376
|
It can be useful when your schemas are stored in another data structure that is
|
|
1365
|
-
unknown to Fastify.
|
|
1366
|
-
#2446](https://github.com/fastify/fastify/issues/2446) for an example of what
|
|
1367
|
-
this property helps to resolve.
|
|
1377
|
+
unknown to Fastify.
|
|
1368
1378
|
|
|
1369
1379
|
Another use case is to tweak all the schemas processing. Doing so it is possible
|
|
1370
1380
|
to use Ajv v8 JTD or Standalone feature. To use such as JTD or the Standalone
|
|
@@ -1404,7 +1414,7 @@ const fastify = Fastify({
|
|
|
1404
1414
|
},
|
|
1405
1415
|
|
|
1406
1416
|
/**
|
|
1407
|
-
* The compilers factory
|
|
1417
|
+
* The compilers factory lets you fully control the validator and serializer
|
|
1408
1418
|
* in the Fastify's lifecycle, providing the encapsulation to your compilers.
|
|
1409
1419
|
*/
|
|
1410
1420
|
compilersFactory: {
|
|
@@ -1461,10 +1471,12 @@ lifecycle](./Lifecycle.md#lifecycle). *async-await* is supported as well.
|
|
|
1461
1471
|
You can also register [`preValidation`](./Hooks.md#route-hooks) and
|
|
1462
1472
|
[`preHandler`](./Hooks.md#route-hooks) hooks for the 404 handler.
|
|
1463
1473
|
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1474
|
+
> **Note**
|
|
1475
|
+
> The `preValidation` hook registered using this method will run for a
|
|
1476
|
+
> route that Fastify does not recognize and **not** when a route handler manually
|
|
1477
|
+
> calls [`reply.callNotFound`](./Reply.md#call-not-found). In which case, only
|
|
1478
|
+
> preHandler will be run.
|
|
1479
|
+
|
|
1468
1480
|
|
|
1469
1481
|
```js
|
|
1470
1482
|
fastify.setNotFoundHandler({
|
|
@@ -1495,8 +1507,9 @@ plugins are registered. If you would like to augment the behavior of the default
|
|
|
1495
1507
|
arguments `fastify.setNotFoundHandler()` within the context of these registered
|
|
1496
1508
|
plugins.
|
|
1497
1509
|
|
|
1498
|
-
> Note
|
|
1499
|
-
>
|
|
1510
|
+
> **Note**
|
|
1511
|
+
> Some config properties from the request object will be
|
|
1512
|
+
> undefined inside the custom not found handler. E.g.:
|
|
1500
1513
|
> `request.routerPath`, `routerMethod` and `context.config`.
|
|
1501
1514
|
> This method design goal is to allow calling the common not found route.
|
|
1502
1515
|
> To return a per-route customized 404 response, you can do it in
|
|
@@ -1510,11 +1523,12 @@ will be called whenever an error happens. The handler is bound to the Fastify
|
|
|
1510
1523
|
instance and is fully encapsulated, so different plugins can set different error
|
|
1511
1524
|
handlers. *async-await* is supported as well.
|
|
1512
1525
|
|
|
1513
|
-
|
|
1514
|
-
set it
|
|
1526
|
+
If the error `statusCode` is less than 400, Fastify will automatically
|
|
1527
|
+
set it to 500 before calling the error handler.
|
|
1515
1528
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1529
|
+
> **Note**
|
|
1530
|
+
> `setErrorHandler` will ***not*** catch any error inside
|
|
1531
|
+
> an `onResponse` hook because the response has already been sent to the client.
|
|
1518
1532
|
|
|
1519
1533
|
```js
|
|
1520
1534
|
fastify.setErrorHandler(function (error, request, reply) {
|
|
@@ -1545,10 +1559,10 @@ if (statusCode >= 500) {
|
|
|
1545
1559
|
`fastify.setChildLoggerFactory(factory(logger, bindings, opts, rawReq))`: Set a
|
|
1546
1560
|
function that will be called when creating a child logger instance for each request
|
|
1547
1561
|
which allows for modifying or adding child logger bindings and logger options, or
|
|
1548
|
-
returning a
|
|
1562
|
+
returning a custom child logger implementation.
|
|
1549
1563
|
|
|
1550
|
-
Child logger bindings have a performance advantage over per-log bindings
|
|
1551
|
-
they are pre-
|
|
1564
|
+
Child logger bindings have a performance advantage over per-log bindings because
|
|
1565
|
+
they are pre-serialized by Pino when the child logger is created.
|
|
1552
1566
|
|
|
1553
1567
|
The first parameter is the parent logger instance, followed by the default bindings
|
|
1554
1568
|
and logger options which should be passed to the child logger, and finally
|
|
@@ -1616,7 +1630,7 @@ a custom constraint strategy with the same name.
|
|
|
1616
1630
|
`fastify.printRoutes()`: Fastify router builds a tree of routes for each HTTP
|
|
1617
1631
|
method. If you call the prettyPrint without specifying an HTTP method, it will
|
|
1618
1632
|
merge all the trees into one and print it. The merged tree doesn't represent the
|
|
1619
|
-
internal router structure. **
|
|
1633
|
+
internal router structure. **Do not use it for debugging.**
|
|
1620
1634
|
|
|
1621
1635
|
*Remember to call it inside or after a `ready` call.*
|
|
1622
1636
|
|
|
@@ -1658,8 +1672,8 @@ param. Printed tree will represent the internal router structure.
|
|
|
1658
1672
|
```
|
|
1659
1673
|
|
|
1660
1674
|
`fastify.printRoutes({ commonPrefix: false })` will print compressed trees. This
|
|
1661
|
-
|
|
1662
|
-
It doesn't represent the internal router structure. **
|
|
1675
|
+
may be useful when you have a large number of routes with common prefixes.
|
|
1676
|
+
It doesn't represent the internal router structure. **Do not use it for debugging.**
|
|
1663
1677
|
|
|
1664
1678
|
```js
|
|
1665
1679
|
console.log(fastify.printRoutes({ commonPrefix: false }))
|
|
@@ -1752,7 +1766,7 @@ fastify.ready(() => {
|
|
|
1752
1766
|
<a id="addContentTypeParser"></a>
|
|
1753
1767
|
|
|
1754
1768
|
`fastify.addContentTypeParser(content-type, options, parser)` is used to pass
|
|
1755
|
-
custom parser for a given content type. Useful for adding parsers for custom
|
|
1769
|
+
a custom parser for a given content type. Useful for adding parsers for custom
|
|
1756
1770
|
content types, e.g. `text/json, application/vnd.oasis.opendocument.text`.
|
|
1757
1771
|
`content-type` can be a string, string array or RegExp.
|
|
1758
1772
|
|
|
@@ -1854,7 +1868,7 @@ for more info.
|
|
|
1854
1868
|
`fastify.initialConfig`: Exposes a frozen read-only object registering the
|
|
1855
1869
|
initial options passed down by the user to the Fastify instance.
|
|
1856
1870
|
|
|
1857
|
-
|
|
1871
|
+
The properties that can currently be exposed are:
|
|
1858
1872
|
- connectionTimeout
|
|
1859
1873
|
- keepAliveTimeout
|
|
1860
1874
|
- bodyLimit
|
|
@@ -788,7 +788,7 @@ There are a couple supported import methods with the Fastify type system.
|
|
|
788
788
|
Many type definitions share the same generic parameters; they are all
|
|
789
789
|
documented, in detail, within this section.
|
|
790
790
|
|
|
791
|
-
Most definitions depend on `@node
|
|
791
|
+
Most definitions depend on `@types/node` modules `http`, `https`, and `http2`
|
|
792
792
|
|
|
793
793
|
##### RawServer
|
|
794
794
|
Underlying Node.js server type
|
package/fastify.js
CHANGED
package/lib/errors.js
CHANGED
|
@@ -214,7 +214,7 @@ const codes = {
|
|
|
214
214
|
),
|
|
215
215
|
FST_ERR_REP_ALREADY_SENT: createError(
|
|
216
216
|
'FST_ERR_REP_ALREADY_SENT',
|
|
217
|
-
'Reply was already sent
|
|
217
|
+
'Reply was already sent, did you forget to "return reply" in "%s" (%s)?'
|
|
218
218
|
),
|
|
219
219
|
FST_ERR_REP_SENT_VALUE: createError(
|
|
220
220
|
'FST_ERR_REP_SENT_VALUE',
|
package/lib/reply.js
CHANGED
|
@@ -97,7 +97,7 @@ Object.defineProperties(Reply.prototype, {
|
|
|
97
97
|
|
|
98
98
|
// We throw only if sent was overwritten from Fastify
|
|
99
99
|
if (this.sent && this[kReplyHijacked]) {
|
|
100
|
-
throw new FST_ERR_REP_ALREADY_SENT()
|
|
100
|
+
throw new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method)
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
this[kReplyHijacked] = true
|
|
@@ -124,7 +124,7 @@ Reply.prototype.send = function (payload) {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
if (this.sent) {
|
|
127
|
-
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT() }
|
|
127
|
+
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method) })
|
|
128
128
|
return this
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -539,6 +539,18 @@ function wrapOnSendEnd (err, request, reply, payload) {
|
|
|
539
539
|
}
|
|
540
540
|
}
|
|
541
541
|
|
|
542
|
+
function safeWriteHead (reply, statusCode) {
|
|
543
|
+
const res = reply.raw
|
|
544
|
+
try {
|
|
545
|
+
res.writeHead(statusCode, reply[kReplyHeaders])
|
|
546
|
+
} catch (err) {
|
|
547
|
+
if (err.code === 'ERR_HTTP_HEADERS_SENT') {
|
|
548
|
+
reply.log.warn(`Reply was already sent, did you forget to "return reply" in the "${reply.request.raw.url}" (${reply.request.raw.method}) route?`)
|
|
549
|
+
}
|
|
550
|
+
throw err
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
542
554
|
function onSendEnd (reply, payload) {
|
|
543
555
|
const res = reply.raw
|
|
544
556
|
const req = reply.request
|
|
@@ -569,7 +581,7 @@ function onSendEnd (reply, payload) {
|
|
|
569
581
|
reply[kReplyHeaders]['content-length'] = '0'
|
|
570
582
|
}
|
|
571
583
|
|
|
572
|
-
|
|
584
|
+
safeWriteHead(reply, statusCode)
|
|
573
585
|
sendTrailer(payload, res, reply)
|
|
574
586
|
return
|
|
575
587
|
}
|
|
@@ -594,7 +606,7 @@ function onSendEnd (reply, payload) {
|
|
|
594
606
|
}
|
|
595
607
|
}
|
|
596
608
|
|
|
597
|
-
|
|
609
|
+
safeWriteHead(reply, statusCode)
|
|
598
610
|
// write payload first
|
|
599
611
|
res.write(payload)
|
|
600
612
|
// then send trailers
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.21.0",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -11,9 +11,8 @@
|
|
|
11
11
|
"benchmark:parser": "npx concurrently -k -s first \"node ./examples/benchmark/parser.js\" \"npx autocannon -c 100 -d 30 -p 10 -i ./examples/benchmark/body.json -H \"content-type:application/jsoff\" -m POST localhost:3000/\"",
|
|
12
12
|
"build:validation": "node build/build-error-serializer.js && node build/build-validation.js",
|
|
13
13
|
"coverage": "npm run unit -- --coverage-report=html",
|
|
14
|
-
"coverage:ci": "
|
|
14
|
+
"coverage:ci": "c8 --reporter=lcov tap --coverage-report=html --no-browser --no-check-coverage",
|
|
15
15
|
"coverage:ci-check-coverage": "c8 check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
|
|
16
|
-
"license-checker": "license-checker --production --onlyAllow=\"MIT;ISC;BSD-3-Clause;BSD-2-Clause\"",
|
|
17
16
|
"lint": "npm run lint:standard && npm run lint:typescript && npm run lint:markdown",
|
|
18
17
|
"lint:fix": "standard --fix",
|
|
19
18
|
"lint:markdown": "markdownlint-cli2",
|
|
@@ -162,10 +161,8 @@
|
|
|
162
161
|
"joi": "^17.9.2",
|
|
163
162
|
"json-schema-to-ts": "^2.9.1",
|
|
164
163
|
"JSONStream": "^1.3.5",
|
|
165
|
-
"license-checker": "^25.0.1",
|
|
166
164
|
"markdownlint-cli2": "^0.8.1",
|
|
167
165
|
"proxyquire": "^2.1.3",
|
|
168
|
-
"pump": "^3.0.0",
|
|
169
166
|
"self-cert": "^2.0.0",
|
|
170
167
|
"send": "^0.18.0",
|
|
171
168
|
"simple-get": "^4.0.1",
|
package/test/async-await.test.js
CHANGED
|
@@ -124,7 +124,7 @@ test('ignore the result of the promise if reply.send is called beforehand (objec
|
|
|
124
124
|
})
|
|
125
125
|
|
|
126
126
|
test('server logs an error if reply.send is called and a value is returned via async/await', t => {
|
|
127
|
-
const lines = ['incoming request', 'request completed', 'Reply already sent']
|
|
127
|
+
const lines = ['incoming request', 'request completed', 'Reply was already sent, did you forget to "return reply" in "/" (GET)?']
|
|
128
128
|
t.plan(lines.length + 2)
|
|
129
129
|
|
|
130
130
|
const splitStream = split(JSON.parse)
|
|
@@ -339,10 +339,10 @@ test('FST_ERR_REP_INVALID_PAYLOAD_TYPE', t => {
|
|
|
339
339
|
|
|
340
340
|
test('FST_ERR_REP_ALREADY_SENT', t => {
|
|
341
341
|
t.plan(5)
|
|
342
|
-
const error = new errors.FST_ERR_REP_ALREADY_SENT()
|
|
342
|
+
const error = new errors.FST_ERR_REP_ALREADY_SENT('/hello', 'GET')
|
|
343
343
|
t.equal(error.name, 'FastifyError')
|
|
344
344
|
t.equal(error.code, 'FST_ERR_REP_ALREADY_SENT')
|
|
345
|
-
t.equal(error.message, 'Reply was already sent
|
|
345
|
+
t.equal(error.message, 'Reply was already sent, did you forget to "return reply" in "/hello" (GET)?')
|
|
346
346
|
t.equal(error.statusCode, 500)
|
|
347
347
|
t.ok(error instanceof Error)
|
|
348
348
|
})
|
|
@@ -1508,7 +1508,7 @@ test('should throw error when passing falsy value to reply.sent', t => {
|
|
|
1508
1508
|
})
|
|
1509
1509
|
|
|
1510
1510
|
test('should throw error when attempting to set reply.sent more than once', t => {
|
|
1511
|
-
t.plan(
|
|
1511
|
+
t.plan(3)
|
|
1512
1512
|
const fastify = Fastify()
|
|
1513
1513
|
|
|
1514
1514
|
fastify.get('/', function (req, reply) {
|
|
@@ -1518,7 +1518,6 @@ test('should throw error when attempting to set reply.sent more than once', t =>
|
|
|
1518
1518
|
t.fail('must throw')
|
|
1519
1519
|
} catch (err) {
|
|
1520
1520
|
t.equal(err.code, 'FST_ERR_REP_ALREADY_SENT')
|
|
1521
|
-
t.equal(err.message, 'Reply was already sent.')
|
|
1522
1521
|
}
|
|
1523
1522
|
reply.raw.end()
|
|
1524
1523
|
})
|
|
@@ -2088,3 +2087,35 @@ test('invalid response headers and custom error handler', async t => {
|
|
|
2088
2087
|
|
|
2089
2088
|
await fastify.close()
|
|
2090
2089
|
})
|
|
2090
|
+
|
|
2091
|
+
test('reply.send will intercept ERR_HTTP_HEADERS_SENT and log an error message', t => {
|
|
2092
|
+
t.plan(2)
|
|
2093
|
+
|
|
2094
|
+
const response = new Writable()
|
|
2095
|
+
Object.assign(response, {
|
|
2096
|
+
setHeader: () => {},
|
|
2097
|
+
hasHeader: () => false,
|
|
2098
|
+
getHeader: () => undefined,
|
|
2099
|
+
writeHead: () => {
|
|
2100
|
+
const err = new Error('kaboom')
|
|
2101
|
+
err.code = 'ERR_HTTP_HEADERS_SENT'
|
|
2102
|
+
throw err
|
|
2103
|
+
},
|
|
2104
|
+
write: () => {},
|
|
2105
|
+
headersSent: true
|
|
2106
|
+
})
|
|
2107
|
+
|
|
2108
|
+
const log = {
|
|
2109
|
+
warn: (msg) => {
|
|
2110
|
+
t.equal(msg, 'Reply was already sent, did you forget to "return reply" in the "/hello" (GET) route?')
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
const reply = new Reply(response, { [kRouteContext]: { onSend: null }, raw: { url: '/hello', method: 'GET' } }, log)
|
|
2115
|
+
|
|
2116
|
+
try {
|
|
2117
|
+
reply.send('')
|
|
2118
|
+
} catch (err) {
|
|
2119
|
+
t.equal(err.code, 'ERR_HTTP_HEADERS_SENT')
|
|
2120
|
+
}
|
|
2121
|
+
})
|
|
@@ -519,7 +519,12 @@ t.test('test log stream', (t) => {
|
|
|
519
519
|
})
|
|
520
520
|
|
|
521
521
|
t.test('reply.send logs an error if called twice in a row', async (t) => {
|
|
522
|
-
const lines = [
|
|
522
|
+
const lines = [
|
|
523
|
+
'incoming request',
|
|
524
|
+
'request completed',
|
|
525
|
+
'Reply was already sent, did you forget to "return reply" in "/" (GET)?',
|
|
526
|
+
'Reply was already sent, did you forget to "return reply" in "/" (GET)?'
|
|
527
|
+
]
|
|
523
528
|
t.plan(lines.length + 1)
|
|
524
529
|
|
|
525
530
|
const stream = split(JSON.parse)
|
package/test/stream.test.js
CHANGED
|
@@ -7,7 +7,7 @@ const sget = require('simple-get').concat
|
|
|
7
7
|
const fs = require('fs')
|
|
8
8
|
const resolve = require('path').resolve
|
|
9
9
|
const zlib = require('zlib')
|
|
10
|
-
const
|
|
10
|
+
const pipeline = require('stream').pipeline
|
|
11
11
|
const Fastify = require('..')
|
|
12
12
|
const errors = require('http-errors')
|
|
13
13
|
const JSONStream = require('JSONStream')
|
|
@@ -139,7 +139,7 @@ test('onSend hook stream', t => {
|
|
|
139
139
|
const gzStream = zlib.createGzip()
|
|
140
140
|
|
|
141
141
|
reply.header('Content-Encoding', 'gzip')
|
|
142
|
-
|
|
142
|
+
pipeline(
|
|
143
143
|
fs.createReadStream(resolve(process.cwd() + '/test/stream.test.js'), 'utf8'),
|
|
144
144
|
gzStream,
|
|
145
145
|
t.error
|
|
@@ -637,7 +637,7 @@ test('should destroy stream when response is ended', t => {
|
|
|
637
637
|
|
|
638
638
|
fastify.get('/error', function (req, reply) {
|
|
639
639
|
const reallyLongStream = new stream.Readable({
|
|
640
|
-
read: function () {},
|
|
640
|
+
read: function () { },
|
|
641
641
|
destroy: function (err, callback) {
|
|
642
642
|
t.ok('called')
|
|
643
643
|
callback(err)
|
|
@@ -763,7 +763,7 @@ test('request terminated should not crash fastify', t => {
|
|
|
763
763
|
|
|
764
764
|
fastify.get('/', async (req, reply) => {
|
|
765
765
|
const stream = new Readable()
|
|
766
|
-
stream._read = () => {}
|
|
766
|
+
stream._read = () => { }
|
|
767
767
|
reply.header('content-type', 'text/html; charset=utf-8')
|
|
768
768
|
reply.header('transfer-encoding', 'chunked')
|
|
769
769
|
stream.push('<h1>HTML</h1>')
|
|
@@ -53,6 +53,10 @@ interface ReplyPayload {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
interface ReplyArrayPayload {
|
|
57
|
+
Reply: string[]
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
interface ReplyUnion {
|
|
57
61
|
Reply: {
|
|
58
62
|
success: boolean;
|
|
@@ -70,6 +74,14 @@ interface ReplyHttpCodes {
|
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
interface InvalidReplyHttpCodes {
|
|
78
|
+
Reply: {
|
|
79
|
+
'1xx': number,
|
|
80
|
+
200: string,
|
|
81
|
+
999: boolean,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
const typedHandler: RouteHandler<ReplyPayload> = async (request, reply) => {
|
|
74
86
|
expectType<((payload?: ReplyPayload['Reply']) => FastifyReply<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>, ReplyPayload>)>(reply.send)
|
|
75
87
|
expectType<((payload?: ReplyPayload['Reply']) => FastifyReply<RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>, ReplyPayload>)>(reply.code(100).send)
|
|
@@ -137,3 +149,16 @@ expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-4', a
|
|
|
137
149
|
expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-5', async function handler (request, reply) {
|
|
138
150
|
reply.code(401).send({ foo: 123 })
|
|
139
151
|
}))
|
|
152
|
+
server.get<ReplyArrayPayload>('/get-generic-array-send', async function handler (request, reply) {
|
|
153
|
+
reply.code(200).send([''])
|
|
154
|
+
})
|
|
155
|
+
expectError(server.get<InvalidReplyHttpCodes>('get-invalid-http-codes-reply-error', async function handler (request, reply) {
|
|
156
|
+
reply.code(200).send('')
|
|
157
|
+
}))
|
|
158
|
+
server.get<InvalidReplyHttpCodes>('get-invalid-http-codes-reply-error', async function handler (request, reply) {
|
|
159
|
+
reply.code(200).send({
|
|
160
|
+
'1xx': 0,
|
|
161
|
+
200: '',
|
|
162
|
+
999: false
|
|
163
|
+
})
|
|
164
|
+
})
|
|
@@ -278,6 +278,62 @@ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
|
|
|
278
278
|
}
|
|
279
279
|
))
|
|
280
280
|
|
|
281
|
+
// -------------------------------------------------------------------
|
|
282
|
+
// Request headers
|
|
283
|
+
// -------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
// JsonSchemaToTsProvider
|
|
286
|
+
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
|
|
287
|
+
'/',
|
|
288
|
+
{
|
|
289
|
+
schema: {
|
|
290
|
+
headers: {
|
|
291
|
+
type: 'object',
|
|
292
|
+
properties: {
|
|
293
|
+
lowercase: { type: 'string' },
|
|
294
|
+
UPPERCASE: { type: 'number' },
|
|
295
|
+
camelCase: { type: 'boolean' },
|
|
296
|
+
'KEBAB-case': { type: 'boolean' },
|
|
297
|
+
PRESERVE_OPTIONAL: { type: 'number' }
|
|
298
|
+
},
|
|
299
|
+
required: ['lowercase', 'UPPERCASE', 'camelCase', 'KEBAB-case']
|
|
300
|
+
} as const
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
(req) => {
|
|
304
|
+
expectType<string>(req.headers.lowercase)
|
|
305
|
+
expectType<string | string[] | undefined>(req.headers.UPPERCASE)
|
|
306
|
+
expectType<number>(req.headers.uppercase)
|
|
307
|
+
expectType<boolean>(req.headers.camelcase)
|
|
308
|
+
expectType<boolean>(req.headers['kebab-case'])
|
|
309
|
+
expectType<number | undefined>(req.headers.preserve_optional)
|
|
310
|
+
}
|
|
311
|
+
))
|
|
312
|
+
|
|
313
|
+
// TypeBoxProvider
|
|
314
|
+
expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
|
|
315
|
+
'/',
|
|
316
|
+
{
|
|
317
|
+
schema: {
|
|
318
|
+
headers: Type.Object({
|
|
319
|
+
lowercase: Type.String(),
|
|
320
|
+
UPPERCASE: Type.Number(),
|
|
321
|
+
camelCase: Type.Boolean(),
|
|
322
|
+
'KEBAB-case': Type.Boolean(),
|
|
323
|
+
PRESERVE_OPTIONAL: Type.Optional(Type.Number())
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
(req) => {
|
|
328
|
+
expectType<string>(req.headers.lowercase)
|
|
329
|
+
expectType<string | string[] | undefined>(req.headers.UPPERCASE)
|
|
330
|
+
expectType<number>(req.headers.uppercase)
|
|
331
|
+
expectType<boolean>(req.headers.camelcase)
|
|
332
|
+
expectType<boolean>(req.headers['kebab-case'])
|
|
333
|
+
expectType<number | undefined>(req.headers.preserve_optional)
|
|
334
|
+
}
|
|
335
|
+
))
|
|
336
|
+
|
|
281
337
|
// -------------------------------------------------------------------
|
|
282
338
|
// TypeBox Reply Type
|
|
283
339
|
// -------------------------------------------------------------------
|
package/types/reply.d.ts
CHANGED
|
@@ -6,17 +6,19 @@ import { FastifyRequest } from './request'
|
|
|
6
6
|
import { RouteGenericInterface } from './route'
|
|
7
7
|
import { FastifySchema } from './schema'
|
|
8
8
|
import { FastifyReplyType, FastifyTypeProvider, FastifyTypeProviderDefault, ResolveFastifyReplyType } from './type-provider'
|
|
9
|
-
import { CodeToReplyKey, ContextConfigDefault, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, ReplyDefault, ReplyKeysToCodes } from './utils'
|
|
9
|
+
import { CodeToReplyKey, ContextConfigDefault, HttpKeys, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, ReplyDefault, ReplyKeysToCodes } from './utils'
|
|
10
10
|
|
|
11
11
|
export interface ReplyGenericInterface {
|
|
12
12
|
Reply?: ReplyDefault;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
type HttpCodesReplyType = Partial<Record<HttpKeys, unknown>>
|
|
16
|
+
|
|
17
|
+
type ReplyTypeConstrainer<RouteGenericReply, Code extends ReplyKeysToCodes<keyof RouteGenericReply>> =
|
|
18
|
+
RouteGenericReply extends HttpCodesReplyType & Record<Exclude<keyof RouteGenericReply, keyof HttpCodesReplyType>, never> ?
|
|
19
|
+
Code extends keyof RouteGenericReply ? RouteGenericReply[Code] :
|
|
20
|
+
CodeToReplyKey<Code> extends keyof RouteGenericReply ? RouteGenericReply[CodeToReplyKey<Code>] : unknown :
|
|
21
|
+
RouteGenericReply;
|
|
20
22
|
|
|
21
23
|
export type ResolveReplyTypeWithRouteGeneric<RouteGenericReply, Code extends ReplyKeysToCodes<keyof RouteGenericReply>,
|
|
22
24
|
SchemaCompiler extends FastifySchema = FastifySchema,
|
package/types/type-provider.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RouteGenericInterface } from './route'
|
|
2
2
|
import { FastifySchema } from './schema'
|
|
3
|
+
import { RecordKeysToLowercase } from './utils'
|
|
3
4
|
|
|
4
5
|
// -----------------------------------------------------------------------------------------------
|
|
5
6
|
// TypeProvider
|
|
@@ -51,7 +52,7 @@ export interface FastifyRequestType<Params = unknown, Querystring = unknown, Hea
|
|
|
51
52
|
export interface ResolveFastifyRequestType<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> extends FastifyRequestType {
|
|
52
53
|
params: ResolveRequestParams<TypeProvider, SchemaCompiler, RouteGeneric>,
|
|
53
54
|
query: ResolveRequestQuerystring<TypeProvider, SchemaCompiler, RouteGeneric>,
|
|
54
|
-
headers: ResolveRequestHeaders<TypeProvider, SchemaCompiler, RouteGeneric
|
|
55
|
+
headers: RecordKeysToLowercase<ResolveRequestHeaders<TypeProvider, SchemaCompiler, RouteGeneric>>,
|
|
55
56
|
body: ResolveRequestBody<TypeProvider, SchemaCompiler, RouteGeneric>
|
|
56
57
|
}
|
|
57
58
|
|
package/types/utils.d.ts
CHANGED
|
@@ -69,3 +69,12 @@ export type ReplyKeysToCodes<Key> = [Key] extends [never] ? number :
|
|
|
69
69
|
export type CodeToReplyKey<Code extends number> = `${Code}` extends `${infer FirstDigit extends CodeClasses}${number}`
|
|
70
70
|
? `${FirstDigit}xx`
|
|
71
71
|
: never;
|
|
72
|
+
|
|
73
|
+
export type RecordKeysToLowercase<Input> = Input extends Record<string, unknown>
|
|
74
|
+
? {
|
|
75
|
+
[Key in keyof Input as Key extends string
|
|
76
|
+
? Lowercase<Key>
|
|
77
|
+
: Key
|
|
78
|
+
]: Input[Key];
|
|
79
|
+
}
|
|
80
|
+
: Input;
|