fastify 5.6.0 → 5.6.2
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/.vscode/settings.json +22 -0
- package/SECURITY.md +12 -0
- package/SPONSORS.md +1 -0
- package/build/build-validation.js +1 -1
- package/build/sync-version.js +1 -0
- package/docs/Guides/Ecosystem.md +5 -0
- package/docs/Guides/Fluent-Schema.md +2 -2
- package/docs/Reference/Decorators.md +36 -169
- package/docs/Reference/Encapsulation.md +5 -1
- package/docs/Reference/Plugins.md +11 -2
- package/docs/Reference/Reply.md +4 -1
- package/docs/Reference/Server.md +39 -1
- package/docs/Reference/Type-Providers.md +2 -2
- package/docs/Reference/TypeScript.md +136 -0
- package/eslint.config.js +18 -2
- package/fastify.d.ts +1 -1
- package/fastify.js +183 -168
- package/lib/{contentTypeParser.js → content-type-parser.js} +2 -1
- package/lib/error-handler.js +2 -2
- package/lib/{fourOhFour.js → four-oh-four.js} +4 -2
- package/lib/{handleRequest.js → handle-request.js} +1 -1
- package/lib/{headRoute.js → head-route.js} +13 -1
- package/lib/{initialConfigValidation.js → initial-config-validation.js} +1 -1
- package/lib/{pluginOverride.js → plugin-override.js} +2 -2
- package/lib/{pluginUtils.js → plugin-utils.js} +2 -2
- package/lib/reply.js +5 -3
- package/lib/request.js +5 -0
- package/lib/route.js +20 -9
- package/lib/server.js +94 -8
- package/lib/symbols.js +1 -0
- package/lib/validation.js +9 -1
- package/lib/warnings.js +1 -1
- package/package.json +8 -8
- package/test/500s.test.js +191 -0
- package/test/child-logger-factory.test.js +3 -3
- package/test/content-parser.test.js +2 -1
- package/test/decorator-namespace.test._js_ +1 -1
- package/test/diagnostics-channel/error-before-handler.test.js +1 -1
- package/test/http2/closing.test.js +88 -0
- package/test/internals/content-type-parser.test.js +2 -2
- package/test/internals/handle-request.test.js +2 -2
- package/test/internals/initial-config.test.js +1 -1
- package/test/internals/plugin.test.js +2 -2
- package/test/internals/reply.test.js +22 -3
- package/test/internals/req-id-gen-factory.test.js +1 -1
- package/test/promises.test.js +3 -3
- package/test/reply-web-stream-locked.test.js +37 -0
- package/test/request-error.test.js +116 -0
- package/test/route.6.test.js +20 -1
- package/test/route.7.test.js +49 -0
- package/test/schema-validation.test.js +27 -4
- package/test/server.test.js +22 -4
- package/test/set-error-handler.test.js +1 -1
- package/test/skip-reply-send.test.js +2 -2
- package/test/stream.5.test.js +3 -3
- package/test/types/fastify.test-d.ts +70 -18
- package/test/types/hooks.test-d.ts +6 -1
- package/test/types/instance.test-d.ts +35 -15
- package/test/types/logger.test-d.ts +18 -6
- package/test/types/plugin.test-d.ts +24 -6
- package/test/types/register.test-d.ts +108 -33
- package/test/types/reply.test-d.ts +23 -6
- package/test/types/request.test-d.ts +25 -6
- package/test/types/route.test-d.ts +10 -1
- package/test/types/schema.test-d.ts +21 -0
- package/test/validation-error-handling.test.js +68 -1
- package/test/wrap-thenable.test.js +1 -1
- package/types/instance.d.ts +2 -2
- package/types/schema.d.ts +1 -1
- package/test/check.test.js +0 -219
- /package/lib/{configValidator.js → config-validator.js} +0 -0
- /package/lib/{reqIdGenFactory.js → req-id-gen-factory.js} +0 -0
- /package/lib/{wrapThenable.js → wrap-thenable.js} +0 -0
- /package/types/{serverFactory.d.ts → server-factory.d.ts} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workbench.colorCustomizations": {
|
|
3
|
+
"[GitHub Dark]": {
|
|
4
|
+
"tab.activeBackground": "#0d0d0d",
|
|
5
|
+
"tab.activeBorder": "#ffff00"
|
|
6
|
+
},
|
|
7
|
+
"activityBar.background": "#FBE7B2",
|
|
8
|
+
"activityBar.foreground": "#52358C",
|
|
9
|
+
"activityBar.inactiveForeground": "#616161",
|
|
10
|
+
"activityBar.activeBorder": "#04184d",
|
|
11
|
+
"activityBar.activeBackground": "#C3B48B",
|
|
12
|
+
"activityBar.border": "#C3B48B",
|
|
13
|
+
"titleBar.activeBackground": "#D2BE88",
|
|
14
|
+
"titleBar.activeForeground": "#52358C",
|
|
15
|
+
"titleBar.inactiveBackground": "#bdb59c",
|
|
16
|
+
"titleBar.inactiveForeground": "#616161",
|
|
17
|
+
"titleBar.border": "#C3B48B",
|
|
18
|
+
"statusBar.background": "#E9DBB7",
|
|
19
|
+
"statusBar.foreground": "#52358C",
|
|
20
|
+
"statusBar.border": "#C3B48B"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/SECURITY.md
CHANGED
|
@@ -110,6 +110,18 @@ Within HackerOne, this is handled through a "public disclosure request".
|
|
|
110
110
|
Reference: [HackerOne:
|
|
111
111
|
Disclosure](https://docs.hackerone.com/hackers/disclosure.html)
|
|
112
112
|
|
|
113
|
+
### Secondary Contact
|
|
114
|
+
|
|
115
|
+
If you do not receive an acknowledgment of your report within 6 business days,
|
|
116
|
+
or if you cannot find a private security contact for the project, you may
|
|
117
|
+
contact the OpenJS Foundation CNA at `security@lists.openjsf.org` for
|
|
118
|
+
assistance.
|
|
119
|
+
|
|
120
|
+
The CNA can help ensure your report is properly acknowledged, assist with
|
|
121
|
+
coordinating disclosure timelines, and assign CVEs when necessary. This is a
|
|
122
|
+
support mechanism to ensure security reports are handled appropriately across
|
|
123
|
+
all OpenJS Foundation projects.
|
|
124
|
+
|
|
113
125
|
## The Fastify Security team
|
|
114
126
|
|
|
115
127
|
The core team is responsible for the management of the security program and
|
package/SPONSORS.md
CHANGED
|
@@ -17,6 +17,7 @@ _Be the first!_
|
|
|
17
17
|
- [Val Town, Inc.](https://opencollective.com/valtown)
|
|
18
18
|
- [Handsontable - JavaScript Data Grid](https://handsontable.com/docs/react-data-grid/?utm_source=Fastify_GH&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024)
|
|
19
19
|
- [Lokalise - A Localization and Translation Software Tool](https://lokalise.com/?utm_source=Fastify_GH&utm_medium=sponsorship)
|
|
20
|
+
- [Lambdatest](https://www.lambdatest.com/)
|
|
20
21
|
|
|
21
22
|
## Tier 2
|
|
22
23
|
|
|
@@ -16,7 +16,7 @@ module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
|
|
|
16
16
|
/* c8 ignore stop */
|
|
17
17
|
`
|
|
18
18
|
|
|
19
|
-
const file = path.join(__dirname, '..', 'lib', '
|
|
19
|
+
const file = path.join(__dirname, '..', 'lib', 'config-validator.js')
|
|
20
20
|
fs.writeFileSync(file, moduleCode)
|
|
21
21
|
console.log(`Saved ${file} file successfully`)
|
|
22
22
|
}
|
package/build/sync-version.js
CHANGED
|
@@ -9,3 +9,4 @@ const { version } = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'packa
|
|
|
9
9
|
const fastifyJs = path.join(__dirname, '..', 'fastify.js')
|
|
10
10
|
|
|
11
11
|
fs.writeFileSync(fastifyJs, fs.readFileSync(fastifyJs).toString('utf8').replace(/const\s*VERSION\s*=.*/, `const VERSION = '${version}'`))
|
|
12
|
+
console.log(`Synchronized fastify.js VERSION to ${version}`)
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -119,6 +119,8 @@ section.
|
|
|
119
119
|
HTTP errors and assertions, but also more request and reply methods.
|
|
120
120
|
- [`@fastify/session`](https://github.com/fastify/session) a session plugin for
|
|
121
121
|
Fastify.
|
|
122
|
+
- [`@fastify/sse`](https://github.com/fastify/sse) Plugin for Server-Sent Events
|
|
123
|
+
(SSE) support in Fastify.
|
|
122
124
|
- [`@fastify/static`](https://github.com/fastify/fastify-static) Plugin for
|
|
123
125
|
serving static files as fast as possible.
|
|
124
126
|
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
|
|
@@ -165,6 +167,9 @@ section.
|
|
|
165
167
|
A simple way to add a crud in your fastify project.
|
|
166
168
|
- [`@applicazza/fastify-nextjs`](https://github.com/applicazza/fastify-nextjs)
|
|
167
169
|
Alternate Fastify and Next.js integration.
|
|
170
|
+
- [`@attaryz/fastify-devtools`](https://github.com/attaryz/fastify-devtools)
|
|
171
|
+
Development tools plugin for Fastify with live request dashboard, replay
|
|
172
|
+
capabilities, and metrics tracking.
|
|
168
173
|
- [`@blastorg/fastify-aws-dynamodb-cache`](https://github.com/blastorg/fastify-aws-dynamodb-cache)
|
|
169
174
|
A plugin to help with caching API responses using AWS DynamoDB.
|
|
170
175
|
- [`@clerk/fastify`](https://github.com/clerkinc/javascript/tree/main/packages/fastify)
|
|
@@ -122,5 +122,5 @@ const schema = { body: bodyJsonSchema }
|
|
|
122
122
|
fastify.post('/the/url', { schema }, handler)
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
`fastify.addSchema`.
|
|
125
|
+
> ℹ️ Note: You can mix up the `$ref-way` and the `replace-way`
|
|
126
|
+
> when using `fastify.addSchema`.
|
|
@@ -366,201 +366,68 @@ Will define the `foo` property on the Fastify instance:
|
|
|
366
366
|
console.log(fastify.foo) // 'a getter'
|
|
367
367
|
```
|
|
368
368
|
|
|
369
|
-
|
|
369
|
+
#### `getDecorator(name)`
|
|
370
|
+
<a id="get-decorator"></a>
|
|
370
371
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
`FST_ERR_DEC_UNDECLARED` error is thrown.
|
|
372
|
+
Used to retrieve an existing decorator from the Fastify instance, `Request`, or `Reply`.
|
|
373
|
+
If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
|
|
374
374
|
|
|
375
|
-
|
|
375
|
+
```js
|
|
376
|
+
// Get a decorator from the Fastify instance
|
|
377
|
+
const utility = fastify.getDecorator('utility')
|
|
376
378
|
|
|
377
|
-
|
|
379
|
+
// Get a decorator from the request object
|
|
380
|
+
const user = request.getDecorator('user')
|
|
378
381
|
|
|
379
|
-
|
|
380
|
-
|
|
382
|
+
// Get a decorator from the reply object
|
|
383
|
+
const helper = reply.getDecorator('helper')
|
|
384
|
+
```
|
|
381
385
|
|
|
382
|
-
|
|
386
|
+
The `getDecorator` method is useful for dependency validation - it can be used to
|
|
387
|
+
check for required decorators at registration time. If any are missing, it fails
|
|
388
|
+
at boot, ensuring dependencies are available during the request lifecycle.
|
|
383
389
|
|
|
384
390
|
```js
|
|
385
391
|
fastify.register(async function (fastify) {
|
|
392
|
+
// Verify the decorator exists before using it
|
|
386
393
|
const usersRepository = fastify.getDecorator('usersRepository')
|
|
387
394
|
|
|
388
395
|
fastify.get('/users', async function (request, reply) {
|
|
389
|
-
// We are sure `usersRepository` exists at runtime
|
|
390
396
|
return usersRepository.findAll()
|
|
391
397
|
})
|
|
392
398
|
})
|
|
393
399
|
```
|
|
394
400
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
```ts
|
|
400
|
-
const user = request.user;
|
|
401
|
-
if (user && user.isAdmin) {
|
|
402
|
-
// Execute admin tasks.
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
If `request.user` doesn't exist, then `user` will be set to `undefined`.
|
|
407
|
-
This makes it unclear whether the user is unauthenticated or the decorator is missing.
|
|
408
|
-
|
|
409
|
-
Using `getDecorator` enforces runtime safety:
|
|
410
|
-
|
|
411
|
-
```ts
|
|
412
|
-
// If the decorator is missing, an explicit `FST_ERR_DEC_UNDECLARED`
|
|
413
|
-
// error is thrown immediately.
|
|
414
|
-
const user = request.getDecorator('user');
|
|
415
|
-
if (user && user.isAdmin) {
|
|
416
|
-
// Execute admin tasks.
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**Alternative to Module Augmentation**
|
|
421
|
-
|
|
422
|
-
Decorators are typically typed via module augmentation:
|
|
423
|
-
|
|
424
|
-
```ts
|
|
425
|
-
declare module 'fastify' {
|
|
426
|
-
interface FastifyInstance {
|
|
427
|
-
usersRepository: IUsersRepository
|
|
428
|
-
}
|
|
429
|
-
interface FastifyRequest {
|
|
430
|
-
session: ISession
|
|
431
|
-
}
|
|
432
|
-
interface FastifyReply {
|
|
433
|
-
sendSuccess: SendSuccessFn
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
This approach modifies the Fastify instance globally, which may lead to
|
|
439
|
-
conflicts and inconsistent behavior in multi-server setups or with plugin
|
|
440
|
-
encapsulation.
|
|
441
|
-
|
|
442
|
-
Using `getDecorator<T>` allows to limit types scope:
|
|
443
|
-
|
|
444
|
-
```ts
|
|
445
|
-
serverOne.register(async function (fastify) {
|
|
446
|
-
const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
|
|
447
|
-
'usersRepository'
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
fastify.decorateRequest('session', null)
|
|
451
|
-
fastify.addHook('onRequest', async (req, reply) => {
|
|
452
|
-
// Yes, the request object has a setDecorator method.
|
|
453
|
-
// More information will be provided soon.
|
|
454
|
-
req.setDecorator('session', { user: 'Jean' })
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
fastify.get('/me', (request, reply) => {
|
|
458
|
-
const session = request.getDecorator<ISession>('session')
|
|
459
|
-
reply.send(session)
|
|
460
|
-
})
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
serverTwo.register(async function (fastify) {
|
|
464
|
-
const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
|
|
465
|
-
'usersRepository'
|
|
466
|
-
)
|
|
467
|
-
|
|
468
|
-
fastify.decorateReply('sendSuccess', function (data) {
|
|
469
|
-
return this.send({ success: true })
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
fastify.get('/success', async (request, reply) => {
|
|
473
|
-
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
|
474
|
-
await sendSuccess()
|
|
475
|
-
})
|
|
476
|
-
})
|
|
477
|
-
```
|
|
401
|
+
> ℹ️ Note: For TypeScript users, `getDecorator` supports generic type parameters.
|
|
402
|
+
> See the [TypeScript documentation](/docs/latest/Reference/TypeScript/) for
|
|
403
|
+
> advanced typing examples.
|
|
478
404
|
|
|
479
|
-
####
|
|
405
|
+
#### `setDecorator(name, value)`
|
|
406
|
+
<a id="set-decorator"></a>
|
|
480
407
|
|
|
481
|
-
|
|
482
|
-
|
|
408
|
+
Used to safely update the value of a `Request` decorator.
|
|
409
|
+
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
|
|
483
410
|
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
return this.send({ success: true })
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
export type SendSuccess = typeof sendSuccess
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
However, `getDecorator` returns functions with the `this`
|
|
493
|
-
context already **bound**, meaning the `this` parameter disappears
|
|
494
|
-
from the function signature.
|
|
495
|
-
|
|
496
|
-
To correctly type it, you should use `OmitThisParameter` utility:
|
|
497
|
-
|
|
498
|
-
```ts
|
|
499
|
-
function sendSuccess (this: FastifyReply) {
|
|
500
|
-
return this.send({ success: true })
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
|
|
504
|
-
|
|
505
|
-
fastify.decorateReply('sendSuccess', sendSuccess)
|
|
506
|
-
fastify.get('/success', async (request, reply) => {
|
|
507
|
-
const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
|
|
508
|
-
await sendSuccess()
|
|
509
|
-
})
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
### `Request.setDecorator<T>` Method
|
|
513
|
-
|
|
514
|
-
The `setDecorator<T>` method provides a safe and convenient way to
|
|
515
|
-
update the value of a `Request` decorator.
|
|
516
|
-
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error
|
|
517
|
-
is thrown.
|
|
518
|
-
|
|
519
|
-
#### Use Cases
|
|
520
|
-
|
|
521
|
-
**Runtime Safety**
|
|
522
|
-
|
|
523
|
-
A typical way to set a `Request` decorator looks like this:
|
|
524
|
-
|
|
525
|
-
```ts
|
|
526
|
-
fastify.decorateRequest('user', '')
|
|
527
|
-
fastify.addHook('preHandler', async (req, reply) => {
|
|
528
|
-
req.user = 'Bob Dylan'
|
|
529
|
-
})
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
However, there is no guarantee that the decorator actually exists
|
|
533
|
-
unless you manually check beforehand.
|
|
534
|
-
Additionally, typos are common, e.g. `account`, `acount`, or `accout`.
|
|
535
|
-
|
|
536
|
-
By using `setDecorator`, you are always sure that the decorator exists:
|
|
411
|
+
```js
|
|
412
|
+
fastify.decorateRequest('user', null)
|
|
537
413
|
|
|
538
|
-
```ts
|
|
539
|
-
fastify.decorateRequest('user', '')
|
|
540
414
|
fastify.addHook('preHandler', async (req, reply) => {
|
|
541
|
-
//
|
|
542
|
-
req.setDecorator('user
|
|
415
|
+
// Safely set the decorator value
|
|
416
|
+
req.setDecorator('user', 'Bob Dylan')
|
|
543
417
|
})
|
|
544
418
|
```
|
|
545
419
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
**Type Safety**
|
|
420
|
+
The `setDecorator` method provides runtime safety by ensuring the decorator exists
|
|
421
|
+
before setting its value, preventing errors from typos in decorator names.
|
|
549
422
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
```ts
|
|
423
|
+
```js
|
|
424
|
+
fastify.decorateRequest('account', null)
|
|
554
425
|
fastify.addHook('preHandler', async (req, reply) => {
|
|
555
|
-
|
|
426
|
+
// This will throw FST_ERR_DEC_UNDECLARED due to typo in decorator name
|
|
427
|
+
req.setDecorator('acount', { id: 123 })
|
|
556
428
|
})
|
|
557
429
|
```
|
|
558
430
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
```ts
|
|
563
|
-
fastify.addHook('preHandler', async (req, reply) => {
|
|
564
|
-
req.setDecorator<string>('user', 'Bob Dylan')
|
|
565
|
-
})
|
|
566
|
-
```
|
|
431
|
+
> ℹ️ Note: For TypeScript users, see the
|
|
432
|
+
> [TypeScript documentation](/docs/latest/Reference/TypeScript/) for advanced
|
|
433
|
+
> typing examples using `setDecorator<T>`.
|
|
@@ -27,7 +27,11 @@ registered within its _grandchild context_.
|
|
|
27
27
|
|
|
28
28
|
Given that everything in Fastify is a [plugin](./Plugins.md) except for the
|
|
29
29
|
_root context_, every "context" and "plugin" in this example is a plugin
|
|
30
|
-
that can consist of decorators, hooks, plugins, and routes.
|
|
30
|
+
that can consist of decorators, hooks, plugins, and routes. As plugins, they
|
|
31
|
+
must still signal completion either by returning a Promise (e.g., using `async` functions)
|
|
32
|
+
or by calling the `done` function if using the callback style.
|
|
33
|
+
|
|
34
|
+
To put this
|
|
31
35
|
example into concrete terms, consider a basic scenario of a REST API server
|
|
32
36
|
with three routes: the first route (`/one`) requires authentication, the
|
|
33
37
|
second route (`/two`) does not, and the third route (`/three`) has access to
|
|
@@ -171,18 +171,27 @@ export default plugin
|
|
|
171
171
|
<a id="create-plugin"></a>
|
|
172
172
|
|
|
173
173
|
Creating a plugin is easy. Create a function that takes three parameters: the
|
|
174
|
-
`fastify` instance, an `options` object, and the `done` callback.
|
|
174
|
+
`fastify` instance, an `options` object, and the `done` callback. Alternatively,
|
|
175
|
+
use an `async` function and omit the `done` callback.
|
|
175
176
|
|
|
176
177
|
Example:
|
|
177
178
|
```js
|
|
178
|
-
module.exports = function (fastify, opts, done) {
|
|
179
|
+
module.exports = function callbackPlugin (fastify, opts, done) {
|
|
179
180
|
fastify.decorate('utility', function () {})
|
|
180
181
|
|
|
181
182
|
fastify.get('/', handler)
|
|
182
183
|
|
|
183
184
|
done()
|
|
184
185
|
}
|
|
186
|
+
|
|
187
|
+
// Or using async
|
|
188
|
+
module.exports = async function asyncPlugin (fastify, opts) {
|
|
189
|
+
fastify.decorate('utility', function () {})
|
|
190
|
+
|
|
191
|
+
fastify.get('/', handler)
|
|
192
|
+
}
|
|
185
193
|
```
|
|
194
|
+
|
|
186
195
|
`register` can also be used inside another `register`:
|
|
187
196
|
```js
|
|
188
197
|
module.exports = function (fastify, opts, done) {
|
package/docs/Reference/Reply.md
CHANGED
|
@@ -369,7 +369,7 @@ charset must be set explicitly.
|
|
|
369
369
|
<a id="getserializationfunction"></a>
|
|
370
370
|
|
|
371
371
|
By calling this function using a provided `schema` or `httpStatus`,
|
|
372
|
-
and the optional `contentType`, it will return a `
|
|
372
|
+
and the optional `contentType`, it will return a `serialization` function
|
|
373
373
|
that can be used to serialize diverse inputs. It returns `undefined` if no
|
|
374
374
|
serialization function was found using either of the provided inputs.
|
|
375
375
|
|
|
@@ -688,6 +688,9 @@ If you are sending a stream and you have not set a `'Content-Type'` header,
|
|
|
688
688
|
As noted above, streams are considered to be pre-serialized, so they will be
|
|
689
689
|
sent unmodified without response validation.
|
|
690
690
|
|
|
691
|
+
See special note about error handling for streams in
|
|
692
|
+
[`setErrorHandler`](./Server.md#seterrorhandler).
|
|
693
|
+
|
|
691
694
|
```js
|
|
692
695
|
const fs = require('node:fs')
|
|
693
696
|
|
package/docs/Reference/Server.md
CHANGED
|
@@ -170,6 +170,12 @@ When set to `true`, upon [`close`](#close) the server will iterate the current
|
|
|
170
170
|
persistent connections and [destroy their
|
|
171
171
|
sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror).
|
|
172
172
|
|
|
173
|
+
When used with HTTP/2 server, it will also close all active HTTP/2 sessions.
|
|
174
|
+
|
|
175
|
+
> ℹ️ Note:
|
|
176
|
+
> Since Node.js v24 active sessions are closed by default
|
|
177
|
+
|
|
178
|
+
|
|
173
179
|
> ⚠ Warning:
|
|
174
180
|
> Connections are not inspected to determine if requests have
|
|
175
181
|
> been completed.
|
|
@@ -966,7 +972,7 @@ Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which suppor
|
|
|
966
972
|
separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`.
|
|
967
973
|
This decision originated from [delvedor/find-my-way#76]
|
|
968
974
|
(https://github.com/delvedor/find-my-way/issues/76). Thus, this option will support
|
|
969
|
-
backwards
|
|
975
|
+
backwards compatibility for the need to split on `;`. To enable support for splitting
|
|
970
976
|
on `;` set `useSemicolonDelimiter` to `true`.
|
|
971
977
|
|
|
972
978
|
```js
|
|
@@ -1436,6 +1442,8 @@ fastify.mkcol('/', (req, reply) => {
|
|
|
1436
1442
|
})
|
|
1437
1443
|
```
|
|
1438
1444
|
|
|
1445
|
+
> ⚠ Warning:
|
|
1446
|
+
> `addHttpMethod` overrides existing methods.
|
|
1439
1447
|
|
|
1440
1448
|
#### addSchema
|
|
1441
1449
|
<a id="add-schema"></a>
|
|
@@ -1687,6 +1695,9 @@ set it to 500 before calling the error handler.
|
|
|
1687
1695
|
sent to the client. Use the `onSend` hook instead.
|
|
1688
1696
|
- not found (404) errors. Use [`setNotFoundHandler`](#set-not-found-handler)
|
|
1689
1697
|
instead.
|
|
1698
|
+
- Stream errors thrown during piping into the response socket, as
|
|
1699
|
+
headers/response were already sent to the client.
|
|
1700
|
+
Use custom in-stream data to signal such errors.
|
|
1690
1701
|
|
|
1691
1702
|
```js
|
|
1692
1703
|
fastify.setErrorHandler(function (error, request, reply) {
|
|
@@ -1716,6 +1727,33 @@ if (statusCode >= 500) {
|
|
|
1716
1727
|
> Avoid calling setErrorHandler multiple times in the same scope.
|
|
1717
1728
|
> See [`allowErrorHandlerOverride`](#allowerrorhandleroverride).
|
|
1718
1729
|
|
|
1730
|
+
##### Custom error handler for stream replies
|
|
1731
|
+
<a id="set-error-handler-stream-replies"></a>
|
|
1732
|
+
|
|
1733
|
+
If `Content-Type` differs between the endpoint and error handler, explicitly
|
|
1734
|
+
define it in both. For example, if the endpoint returns an `application/text`
|
|
1735
|
+
stream and the error handler responds with `application/json`, the error handler
|
|
1736
|
+
must explicitly set `Content-Type`. Otherwise, it will fail serialization with
|
|
1737
|
+
a `500` status code. Alternatively, always respond with serialized data in the
|
|
1738
|
+
error handler by manually calling a serialization method (e.g.,
|
|
1739
|
+
`JSON.stringify`).
|
|
1740
|
+
|
|
1741
|
+
```js
|
|
1742
|
+
fastify.setErrorHandler((err, req, reply) => {
|
|
1743
|
+
reply
|
|
1744
|
+
.code(400)
|
|
1745
|
+
.type('application/json')
|
|
1746
|
+
.send({ error: err.message })
|
|
1747
|
+
})
|
|
1748
|
+
```
|
|
1749
|
+
|
|
1750
|
+
```js
|
|
1751
|
+
fastify.setErrorHandler((err, req, reply) => {
|
|
1752
|
+
reply
|
|
1753
|
+
.code(400)
|
|
1754
|
+
.send(JSON.stringify({ error: err.message }))
|
|
1755
|
+
})
|
|
1756
|
+
```
|
|
1719
1757
|
|
|
1720
1758
|
#### setChildLoggerFactory
|
|
1721
1759
|
<a id="set-child-logger-factory"></a>
|
|
@@ -88,8 +88,8 @@ server.get('/route', {
|
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
See the [TypeBox
|
|
91
|
-
documentation](https://github.
|
|
92
|
-
for setting
|
|
91
|
+
documentation](https://sinclairzx81.github.io/typebox/#/docs/overview/2_setup)
|
|
92
|
+
for setting-up AJV to work with TypeBox.
|
|
93
93
|
|
|
94
94
|
### Zod
|
|
95
95
|
|
|
@@ -687,6 +687,142 @@ Or even explicit config on tsconfig
|
|
|
687
687
|
}
|
|
688
688
|
```
|
|
689
689
|
|
|
690
|
+
#### `getDecorator<T>`
|
|
691
|
+
|
|
692
|
+
Fastify's `getDecorator<T>` method retrieves decorators with enhanced type safety.
|
|
693
|
+
|
|
694
|
+
The `getDecorator<T>` method supports generic type parameters for enhanced type safety:
|
|
695
|
+
|
|
696
|
+
```typescript
|
|
697
|
+
// Type-safe decorator retrieval
|
|
698
|
+
const usersRepository = fastify.getDecorator<IUsersRepository>('usersRepository')
|
|
699
|
+
const session = request.getDecorator<ISession>('session')
|
|
700
|
+
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**Alternative to Module Augmentation**
|
|
704
|
+
|
|
705
|
+
Decorators are typically typed via module augmentation:
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
declare module 'fastify' {
|
|
709
|
+
interface FastifyInstance {
|
|
710
|
+
usersRepository: IUsersRepository
|
|
711
|
+
}
|
|
712
|
+
interface FastifyRequest {
|
|
713
|
+
session: ISession
|
|
714
|
+
}
|
|
715
|
+
interface FastifyReply {
|
|
716
|
+
sendSuccess: SendSuccessFn
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
This approach modifies the Fastify instance globally, which may lead to conflicts
|
|
722
|
+
and inconsistent behavior in multi-server setups or with plugin encapsulation.
|
|
723
|
+
|
|
724
|
+
Using `getDecorator<T>` allows limiting types scope:
|
|
725
|
+
|
|
726
|
+
```typescript
|
|
727
|
+
serverOne.register(async function (fastify) {
|
|
728
|
+
const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
|
|
729
|
+
'usersRepository'
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
fastify.decorateRequest('session', null)
|
|
733
|
+
fastify.addHook('onRequest', async (req, reply) => {
|
|
734
|
+
req.setDecorator('session', { user: 'Jean' })
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
fastify.get('/me', (request, reply) => {
|
|
738
|
+
const session = request.getDecorator<ISession>('session')
|
|
739
|
+
reply.send(session)
|
|
740
|
+
})
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
serverTwo.register(async function (fastify) {
|
|
744
|
+
const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
|
|
745
|
+
'usersRepository'
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
fastify.decorateReply('sendSuccess', function (data) {
|
|
749
|
+
return this.send({ success: true })
|
|
750
|
+
})
|
|
751
|
+
|
|
752
|
+
fastify.get('/success', async (request, reply) => {
|
|
753
|
+
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
|
754
|
+
await sendSuccess()
|
|
755
|
+
})
|
|
756
|
+
})
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
**Bound Functions Inference**
|
|
760
|
+
|
|
761
|
+
To save time, it is common to infer function types instead of writing them manually:
|
|
762
|
+
|
|
763
|
+
```typescript
|
|
764
|
+
function sendSuccess (this: FastifyReply) {
|
|
765
|
+
return this.send({ success: true })
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
export type SendSuccess = typeof sendSuccess
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
However, `getDecorator` returns functions with the `this` context already **bound**,
|
|
772
|
+
meaning the `this` parameter disappears from the function signature.
|
|
773
|
+
|
|
774
|
+
To correctly type it, use the `OmitThisParameter` utility:
|
|
775
|
+
|
|
776
|
+
```typescript
|
|
777
|
+
function sendSuccess (this: FastifyReply) {
|
|
778
|
+
return this.send({ success: true })
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
|
|
782
|
+
|
|
783
|
+
fastify.decorateReply('sendSuccess', sendSuccess)
|
|
784
|
+
fastify.get('/success', async (request, reply) => {
|
|
785
|
+
const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
|
|
786
|
+
await sendSuccess()
|
|
787
|
+
})
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
#### `setDecorator<T>`
|
|
791
|
+
|
|
792
|
+
Fastify's `setDecorator<T>` method provides enhanced type safety for updating request
|
|
793
|
+
decorators.
|
|
794
|
+
|
|
795
|
+
The `setDecorator<T>` method provides enhanced type safety for updating request
|
|
796
|
+
decorators:
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
fastify.decorateRequest('user', '')
|
|
800
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
801
|
+
// Type-safe decorator setting
|
|
802
|
+
req.setDecorator<string>('user', 'Bob Dylan')
|
|
803
|
+
})
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
**Type Safety Benefits**
|
|
807
|
+
|
|
808
|
+
If the `FastifyRequest` interface does not declare the decorator, type assertions
|
|
809
|
+
are typically needed:
|
|
810
|
+
|
|
811
|
+
```typescript
|
|
812
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
813
|
+
(req as typeof req & { user: string }).user = 'Bob Dylan'
|
|
814
|
+
})
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
The `setDecorator<T>` method eliminates the need for explicit type assertions
|
|
818
|
+
while providing type safety:
|
|
819
|
+
|
|
820
|
+
```typescript
|
|
821
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
822
|
+
req.setDecorator<string>('user', 'Bob Dylan')
|
|
823
|
+
})
|
|
824
|
+
```
|
|
825
|
+
|
|
690
826
|
## Code Completion In Vanilla JavaScript
|
|
691
827
|
|
|
692
828
|
Vanilla JavaScript can use the published types to provide code completion (e.g.
|
package/eslint.config.js
CHANGED
|
@@ -4,7 +4,7 @@ const neostandard = require('neostandard')
|
|
|
4
4
|
module.exports = [
|
|
5
5
|
...neostandard({
|
|
6
6
|
ignores: [
|
|
7
|
-
'lib/
|
|
7
|
+
'lib/config-validator.js',
|
|
8
8
|
'lib/error-serializer.js',
|
|
9
9
|
'test/same-shape.test.js',
|
|
10
10
|
'test/types/import.js'
|
|
@@ -13,7 +13,23 @@ module.exports = [
|
|
|
13
13
|
}),
|
|
14
14
|
{
|
|
15
15
|
rules: {
|
|
16
|
-
'comma-dangle': ['error', 'never']
|
|
16
|
+
'comma-dangle': ['error', 'never'],
|
|
17
|
+
'max-len': ['error', {
|
|
18
|
+
code: 120,
|
|
19
|
+
tabWidth: 2,
|
|
20
|
+
ignoreUrls: true,
|
|
21
|
+
ignoreStrings: true,
|
|
22
|
+
ignoreTemplateLiterals: true,
|
|
23
|
+
ignoreRegExpLiterals: true,
|
|
24
|
+
ignoreComments: true,
|
|
25
|
+
ignoreTrailingComments: true
|
|
26
|
+
}]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
files: ['**/*.d.ts'],
|
|
31
|
+
rules: {
|
|
32
|
+
'max-len': 'off'
|
|
17
33
|
}
|
|
18
34
|
}
|
|
19
35
|
]
|
package/fastify.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { FastifyReply } from './types/reply'
|
|
|
29
29
|
import { FastifyRequest, RequestGenericInterface } from './types/request'
|
|
30
30
|
import { RouteGenericInterface, RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
|
|
31
31
|
import { FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
|
32
|
-
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/
|
|
32
|
+
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/server-factory'
|
|
33
33
|
import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
|
|
34
34
|
import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestBodyDefault, RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from './types/utils'
|
|
35
35
|
|