fastify 5.2.1 → 5.3.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/LICENSE +1 -1
- package/PROJECT_CHARTER.md +7 -7
- package/README.md +24 -25
- package/SPONSORS.md +1 -0
- package/docs/Guides/Benchmarking.md +4 -4
- package/docs/Guides/Database.md +1 -1
- package/docs/Guides/Delay-Accepting-Requests.md +10 -10
- package/docs/Guides/Ecosystem.md +7 -1
- package/docs/Guides/Fluent-Schema.md +1 -1
- package/docs/Guides/Getting-Started.md +9 -5
- package/docs/Guides/Index.md +1 -1
- package/docs/Guides/Migration-Guide-V4.md +1 -1
- package/docs/Guides/Migration-Guide-V5.md +12 -2
- package/docs/Guides/Plugins-Guide.md +6 -6
- package/docs/Guides/Serverless.md +14 -48
- package/docs/Guides/Style-Guide.md +2 -2
- package/docs/Guides/Testing.md +2 -2
- package/docs/Guides/Write-Plugin.md +2 -3
- package/docs/Reference/ContentTypeParser.md +58 -78
- package/docs/Reference/Decorators.md +249 -60
- package/docs/Reference/Encapsulation.md +28 -33
- package/docs/Reference/Errors.md +52 -53
- package/docs/Reference/HTTP2.md +7 -7
- package/docs/Reference/Hooks.md +31 -30
- package/docs/Reference/LTS.md +10 -15
- package/docs/Reference/Lifecycle.md +19 -24
- package/docs/Reference/Logging.md +59 -56
- package/docs/Reference/Middleware.md +19 -19
- package/docs/Reference/Plugins.md +55 -71
- package/docs/Reference/Principles.md +25 -30
- package/docs/Reference/Reply.md +11 -10
- package/docs/Reference/Request.md +89 -98
- package/docs/Reference/Routes.md +108 -128
- package/docs/Reference/Server.md +18 -16
- package/docs/Reference/Type-Providers.md +19 -21
- package/docs/Reference/TypeScript.md +1 -18
- package/docs/Reference/Validation-and-Serialization.md +134 -159
- package/docs/Reference/Warnings.md +22 -25
- package/fastify.js +3 -2
- package/lib/contentTypeParser.js +7 -8
- package/lib/decorate.js +18 -3
- package/lib/error-handler.js +14 -12
- package/lib/errors.js +4 -0
- package/lib/headRoute.js +4 -2
- package/lib/pluginUtils.js +4 -2
- package/lib/reply.js +17 -2
- package/lib/request.js +28 -2
- package/lib/server.js +5 -0
- package/lib/validation.js +1 -1
- package/lib/warnings.js +9 -0
- package/lib/wrapThenable.js +8 -1
- package/package.json +12 -12
- package/test/bundler/esbuild/package.json +1 -1
- package/test/close.test.js +125 -108
- package/test/custom-parser-async.test.js +34 -36
- package/test/custom-parser.4.test.js +55 -38
- package/test/decorator.test.js +174 -4
- package/test/fastify-instance.test.js +12 -2
- package/test/genReqId.test.js +125 -174
- package/test/has-route.test.js +1 -3
- package/test/hooks.on-listen.test.js +17 -14
- package/test/internals/content-type-parser.test.js +1 -1
- package/test/internals/errors.test.js +14 -1
- package/test/issue-4959.test.js +84 -0
- package/test/listen.1.test.js +37 -34
- package/test/listen.2.test.js +50 -40
- package/test/listen.3.test.js +28 -32
- package/test/listen.4.test.js +61 -45
- package/test/listen.5.test.js +23 -0
- package/test/register.test.js +55 -50
- package/test/request-error.test.js +114 -94
- package/test/route-shorthand.test.js +36 -32
- package/test/stream.5.test.js +35 -33
- package/test/throw.test.js +87 -91
- package/test/toolkit.js +32 -0
- package/test/trust-proxy.test.js +23 -23
- package/test/types/instance.test-d.ts +4 -0
- package/test/types/reply.test-d.ts +1 -0
- package/test/types/request.test-d.ts +4 -0
- package/test/types/type-provider.test-d.ts +40 -0
- package/test/upgrade.test.js +32 -33
- package/types/instance.d.ts +6 -0
- package/types/reply.d.ts +1 -0
- package/types/request.d.ts +2 -0
- package/types/type-provider.d.ts +12 -3
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Decorators
|
|
4
4
|
|
|
5
|
-
The decorators API
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
The decorators API customizes core Fastify objects, such as the server instance
|
|
6
|
+
and any request and reply objects used during the HTTP request lifecycle. It
|
|
7
|
+
can attach any type of property to core objects, e.g., functions, plain
|
|
8
|
+
objects, or native types.
|
|
9
9
|
|
|
10
|
-
This API is *synchronous*.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
To learn more, see the [Plugins](./Plugins.md) documentation.
|
|
10
|
+
This API is *synchronous*. Defining a decoration asynchronously could result in
|
|
11
|
+
the Fastify instance booting before the decoration completes. To register an
|
|
12
|
+
asynchronous decoration, use the `register` API with `fastify-plugin`. See the
|
|
13
|
+
[Plugins](./Plugins.md) documentation for more details.
|
|
15
14
|
|
|
16
15
|
Decorating core objects with this API allows the underlying JavaScript engine to
|
|
17
16
|
optimize the handling of server, request, and reply objects. This is
|
|
@@ -35,9 +34,9 @@ fastify.get('/', function (req, reply) {
|
|
|
35
34
|
})
|
|
36
35
|
```
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
The above example mutates the request object after instantiation, causing the
|
|
38
|
+
JavaScript engine to deoptimize access. Using the decoration API avoids this
|
|
39
|
+
deoptimization:
|
|
41
40
|
|
|
42
41
|
```js
|
|
43
42
|
// Decorate request with a 'user' property
|
|
@@ -54,17 +53,13 @@ fastify.get('/', (req, reply) => {
|
|
|
54
53
|
})
|
|
55
54
|
```
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
See [JavaScript engine fundamentals: Shapes and Inline
|
|
66
|
-
Caches](https://mathiasbynens.be/notes/shapes-ics) for more information on this
|
|
67
|
-
topic.
|
|
56
|
+
Keep the initial shape of a decorated field close to its future dynamic value.
|
|
57
|
+
Initialize a decorator as `''` for strings and `null` for objects or functions.
|
|
58
|
+
This works only with value types; reference types will throw an error during
|
|
59
|
+
Fastify startup. See [decorateRequest](#decorate-request) and
|
|
60
|
+
[JavaScript engine fundamentals: Shapes
|
|
61
|
+
and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
|
|
62
|
+
for more information.
|
|
68
63
|
|
|
69
64
|
### Usage
|
|
70
65
|
<a id="usage"></a>
|
|
@@ -72,8 +67,7 @@ topic.
|
|
|
72
67
|
#### `decorate(name, value, [dependencies])`
|
|
73
68
|
<a id="decorate"></a>
|
|
74
69
|
|
|
75
|
-
This method
|
|
76
|
-
instance.
|
|
70
|
+
This method customizes the Fastify [server](./Server.md) instance.
|
|
77
71
|
|
|
78
72
|
For example, to attach a new method to the server instance:
|
|
79
73
|
|
|
@@ -83,7 +77,7 @@ fastify.decorate('utility', function () {
|
|
|
83
77
|
})
|
|
84
78
|
```
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
Non-function values can also be attached to the server instance:
|
|
87
81
|
|
|
88
82
|
```js
|
|
89
83
|
fastify.decorate('conf', {
|
|
@@ -118,9 +112,9 @@ fastify.get('/', async function (request, reply) {
|
|
|
118
112
|
```
|
|
119
113
|
|
|
120
114
|
The `dependencies` parameter is an optional list of decorators that the
|
|
121
|
-
decorator being defined relies upon. This list
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
decorator being defined relies upon. This list contains the names of other
|
|
116
|
+
decorators. In the following example, the "utility" decorator depends on the
|
|
117
|
+
"greet" and "hi" decorators:
|
|
124
118
|
|
|
125
119
|
```js
|
|
126
120
|
async function greetDecorator (fastify, opts) {
|
|
@@ -155,18 +149,17 @@ fastify.listen({ port: 3000 }, (err, address) => {
|
|
|
155
149
|
})
|
|
156
150
|
```
|
|
157
151
|
|
|
158
|
-
|
|
159
|
-
`FastifyInstance`.
|
|
152
|
+
Using an arrow function breaks the binding of `this` to
|
|
153
|
+
the `FastifyInstance`.
|
|
160
154
|
|
|
161
|
-
If a dependency is not satisfied, the `decorate` method
|
|
162
|
-
The dependency check
|
|
163
|
-
|
|
155
|
+
If a dependency is not satisfied, the `decorate` method throws an exception.
|
|
156
|
+
The dependency check occurs before the server instance boots, not during
|
|
157
|
+
runtime.
|
|
164
158
|
|
|
165
159
|
#### `decorateReply(name, value, [dependencies])`
|
|
166
160
|
<a id="decorate-reply"></a>
|
|
167
161
|
|
|
168
|
-
|
|
169
|
-
`Reply` object:
|
|
162
|
+
This API adds new methods/properties to the core `Reply` object:
|
|
170
163
|
|
|
171
164
|
```js
|
|
172
165
|
fastify.decorateReply('utility', function () {
|
|
@@ -174,29 +167,29 @@ fastify.decorateReply('utility', function () {
|
|
|
174
167
|
})
|
|
175
168
|
```
|
|
176
169
|
|
|
177
|
-
|
|
170
|
+
Using an arrow function will break the binding of `this` to the Fastify
|
|
178
171
|
`Reply` instance.
|
|
179
172
|
|
|
180
|
-
|
|
173
|
+
Using `decorateReply` will throw and error if used with a reference type:
|
|
181
174
|
|
|
182
175
|
```js
|
|
183
176
|
// Don't do this
|
|
184
177
|
fastify.decorateReply('foo', { bar: 'fizz'})
|
|
185
178
|
```
|
|
186
|
-
In this example, the reference
|
|
187
|
-
|
|
188
|
-
vulnerabilities or memory leaks
|
|
179
|
+
In this example, the object reference would be shared with all requests, and
|
|
180
|
+
**any mutation will impact all requests, potentially creating security
|
|
181
|
+
vulnerabilities or memory leaks**. Fastify blocks this.
|
|
189
182
|
|
|
190
183
|
To achieve proper encapsulation across requests configure a new value for each
|
|
191
|
-
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
|
|
184
|
+
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
|
|
192
185
|
|
|
193
186
|
```js
|
|
194
187
|
const fp = require('fastify-plugin')
|
|
195
188
|
|
|
196
189
|
async function myPlugin (app) {
|
|
197
|
-
app.
|
|
190
|
+
app.decorateReply('foo')
|
|
198
191
|
app.addHook('onRequest', async (req, reply) => {
|
|
199
|
-
|
|
192
|
+
reply.foo = { bar: 42 }
|
|
200
193
|
})
|
|
201
194
|
}
|
|
202
195
|
|
|
@@ -208,8 +201,8 @@ See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
|
|
208
201
|
#### `decorateRequest(name, value, [dependencies])`
|
|
209
202
|
<a id="decorate-request"></a>
|
|
210
203
|
|
|
211
|
-
As
|
|
212
|
-
|
|
204
|
+
As with [`decorateReply`](#decorate-reply), this API adds new methods/properties
|
|
205
|
+
to the core `Request` object:
|
|
213
206
|
|
|
214
207
|
```js
|
|
215
208
|
fastify.decorateRequest('utility', function () {
|
|
@@ -217,18 +210,18 @@ fastify.decorateRequest('utility', function () {
|
|
|
217
210
|
})
|
|
218
211
|
```
|
|
219
212
|
|
|
220
|
-
|
|
213
|
+
Using an arrow function will break the binding of `this` to the Fastify
|
|
221
214
|
`Request` instance.
|
|
222
215
|
|
|
223
|
-
|
|
216
|
+
Using `decorateRequest` will emit an error if used with a reference type:
|
|
224
217
|
|
|
225
218
|
```js
|
|
226
219
|
// Don't do this
|
|
227
220
|
fastify.decorateRequest('foo', { bar: 'fizz'})
|
|
228
221
|
```
|
|
229
|
-
In this example, the reference
|
|
230
|
-
|
|
231
|
-
vulnerabilities or memory leaks
|
|
222
|
+
In this example, the object reference would be shared with all requests, and
|
|
223
|
+
**any mutation will impact all requests, potentially creating security
|
|
224
|
+
vulnerabilities or memory leaks**. Fastify blocks this.
|
|
232
225
|
|
|
233
226
|
To achieve proper encapsulation across requests configure a new value for each
|
|
234
227
|
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
|
|
@@ -249,7 +242,7 @@ module.exports = fp(myPlugin)
|
|
|
249
242
|
```
|
|
250
243
|
|
|
251
244
|
The hook solution is more flexible and allows for more complex initialization
|
|
252
|
-
because
|
|
245
|
+
because more logic can be added to the `onRequest` hook.
|
|
253
246
|
|
|
254
247
|
Another approach is to use the getter/setter pattern, but it requires 2 decorators:
|
|
255
248
|
|
|
@@ -268,8 +261,7 @@ fastify.get('/', async function (req, reply) {
|
|
|
268
261
|
})
|
|
269
262
|
```
|
|
270
263
|
|
|
271
|
-
This ensures that the `user` property is always unique for each
|
|
272
|
-
request.
|
|
264
|
+
This ensures that the `user` property is always unique for each request.
|
|
273
265
|
|
|
274
266
|
See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
|
275
267
|
|
|
@@ -305,9 +297,7 @@ fastify.hasReplyDecorator('utility')
|
|
|
305
297
|
|
|
306
298
|
Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`)
|
|
307
299
|
with the same name more than once in the same **encapsulated** context will
|
|
308
|
-
throw an exception.
|
|
309
|
-
|
|
310
|
-
As an example, the following will throw:
|
|
300
|
+
throw an exception. For example, the following will throw:
|
|
311
301
|
|
|
312
302
|
```js
|
|
313
303
|
const server = require('fastify')()
|
|
@@ -358,9 +348,9 @@ server.listen({ port: 3000 })
|
|
|
358
348
|
### Getters and Setters
|
|
359
349
|
<a id="getters-setters"></a>
|
|
360
350
|
|
|
361
|
-
Decorators accept special "getter/setter" objects
|
|
362
|
-
|
|
363
|
-
|
|
351
|
+
Decorators accept special "getter/setter" objects with `getter` and optional
|
|
352
|
+
`setter` functions. This allows defining properties via decorators,
|
|
353
|
+
for example:
|
|
364
354
|
|
|
365
355
|
```js
|
|
366
356
|
fastify.decorate('foo', {
|
|
@@ -375,3 +365,202 @@ Will define the `foo` property on the Fastify instance:
|
|
|
375
365
|
```js
|
|
376
366
|
console.log(fastify.foo) // 'a getter'
|
|
377
367
|
```
|
|
368
|
+
|
|
369
|
+
### `getDecorator<T>` API
|
|
370
|
+
|
|
371
|
+
Fastify's `getDecorator<T>` API retrieves an existing decorator from the
|
|
372
|
+
Fastify instance, `Request`, or `Reply`. If the decorator is not defined, an
|
|
373
|
+
`FST_ERR_DEC_UNDECLARED` error is thrown.
|
|
374
|
+
|
|
375
|
+
#### Use cases
|
|
376
|
+
|
|
377
|
+
**Early Plugin Dependency Validation**
|
|
378
|
+
|
|
379
|
+
`getDecorator<T>` on Fastify instance verifies that required decorators are
|
|
380
|
+
available at registration time.
|
|
381
|
+
|
|
382
|
+
For example:
|
|
383
|
+
|
|
384
|
+
```js
|
|
385
|
+
fastify.register(async function (fastify) {
|
|
386
|
+
const usersRepository = fastify.getDecorator('usersRepository')
|
|
387
|
+
|
|
388
|
+
fastify.get('/users', async function (request, reply) {
|
|
389
|
+
// We are sure `usersRepository` exists at runtime
|
|
390
|
+
return usersRepository.findAll()
|
|
391
|
+
})
|
|
392
|
+
})
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Handling Missing Decorators**
|
|
396
|
+
|
|
397
|
+
Directly accessing a decorator may lead to unexpected behavior if it is not declared:
|
|
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
|
+
```
|
|
478
|
+
|
|
479
|
+
#### Bound functions inference
|
|
480
|
+
|
|
481
|
+
To save time, it's common to infer function types instead of
|
|
482
|
+
writing them manually:
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
function sendSuccess (this: FastifyReply) {
|
|
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:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
fastify.decorateRequest('user', '')
|
|
540
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
541
|
+
// Throws FST_ERR_DEC_UNDECLARED if the decorator does not exist
|
|
542
|
+
req.setDecorator('user-with-typo', 'Bob Dylan')
|
|
543
|
+
})
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
**Type Safety**
|
|
549
|
+
|
|
550
|
+
If the `FastifyRequest` interface does not declare the decorator, you
|
|
551
|
+
would typically need to use type assertions:
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
555
|
+
(req as typeof req & { user: string }).user = 'Bob Dylan'
|
|
556
|
+
})
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
The `setDecorator<T>` method eliminates the need for explicit type
|
|
560
|
+
assertions while allowing type safety:
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
fastify.addHook('preHandler', async (req, reply) => {
|
|
564
|
+
req.setDecorator<string>('user', 'Bob Dylan')
|
|
565
|
+
})
|
|
566
|
+
```
|
|
@@ -3,21 +3,20 @@
|
|
|
3
3
|
## Encapsulation
|
|
4
4
|
<a id="encapsulation"></a>
|
|
5
5
|
|
|
6
|
-
A fundamental feature of Fastify is the "encapsulation context."
|
|
7
|
-
|
|
8
|
-
[
|
|
9
|
-
|
|
10
|
-
is shown in the following figure:
|
|
6
|
+
A fundamental feature of Fastify is the "encapsulation context." It governs
|
|
7
|
+
which [decorators](./Decorators.md), registered [hooks](./Hooks.md), and
|
|
8
|
+
[plugins](./Plugins.md) are available to [routes](./Routes.md). A visual
|
|
9
|
+
representation of the encapsulation context is shown in the following figure:
|
|
11
10
|
|
|
12
11
|

|
|
13
12
|
|
|
14
|
-
In the above
|
|
13
|
+
In the figure above, there are several entities:
|
|
15
14
|
|
|
16
15
|
1. The _root context_
|
|
17
16
|
2. Three _root plugins_
|
|
18
|
-
3. Two _child contexts_
|
|
17
|
+
3. Two _child contexts_, each with:
|
|
19
18
|
* Two _child plugins_
|
|
20
|
-
* One _grandchild context_
|
|
19
|
+
* One _grandchild context_, each with:
|
|
21
20
|
- Three _child plugins_
|
|
22
21
|
|
|
23
22
|
Every _child context_ and _grandchild context_ has access to the _root plugins_.
|
|
@@ -26,15 +25,14 @@ _child plugins_ registered within the containing _child context_, but the
|
|
|
26
25
|
containing _child context_ **does not** have access to the _child plugins_
|
|
27
26
|
registered within its _grandchild context_.
|
|
28
27
|
|
|
29
|
-
Given that everything in Fastify is a [plugin](./Plugins.md)
|
|
28
|
+
Given that everything in Fastify is a [plugin](./Plugins.md) except for the
|
|
30
29
|
_root context_, every "context" and "plugin" in this example is a plugin
|
|
31
|
-
that can consist of decorators, hooks, plugins, and routes.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
example is as follows:
|
|
30
|
+
that can consist of decorators, hooks, plugins, and routes. To put this
|
|
31
|
+
example into concrete terms, consider a basic scenario of a REST API server
|
|
32
|
+
with three routes: the first route (`/one`) requires authentication, the
|
|
33
|
+
second route (`/two`) does not, and the third route (`/three`) has access to
|
|
34
|
+
the same context as the second route. Using [@fastify/bearer-auth][bearer] to
|
|
35
|
+
provide authentication, the code for this example is as follows:
|
|
38
36
|
|
|
39
37
|
```js
|
|
40
38
|
'use strict'
|
|
@@ -52,9 +50,9 @@ fastify.register(async function authenticatedContext (childServer) {
|
|
|
52
50
|
handler (request, response) {
|
|
53
51
|
response.send({
|
|
54
52
|
answer: request.answer,
|
|
55
|
-
// request.foo will be undefined as it
|
|
53
|
+
// request.foo will be undefined as it is only defined in publicContext
|
|
56
54
|
foo: request.foo,
|
|
57
|
-
// request.bar will be undefined as it
|
|
55
|
+
// request.bar will be undefined as it is only defined in grandchildContext
|
|
58
56
|
bar: request.bar
|
|
59
57
|
})
|
|
60
58
|
}
|
|
@@ -71,7 +69,7 @@ fastify.register(async function publicContext (childServer) {
|
|
|
71
69
|
response.send({
|
|
72
70
|
answer: request.answer,
|
|
73
71
|
foo: request.foo,
|
|
74
|
-
// request.bar will be undefined as it
|
|
72
|
+
// request.bar will be undefined as it is only defined in grandchildContext
|
|
75
73
|
bar: request.bar
|
|
76
74
|
})
|
|
77
75
|
}
|
|
@@ -97,16 +95,16 @@ fastify.register(async function publicContext (childServer) {
|
|
|
97
95
|
fastify.listen({ port: 8000 })
|
|
98
96
|
```
|
|
99
97
|
|
|
100
|
-
The
|
|
98
|
+
The server example above demonstrates the encapsulation concepts from the
|
|
101
99
|
original diagram:
|
|
102
100
|
|
|
103
101
|
1. Each _child context_ (`authenticatedContext`, `publicContext`, and
|
|
104
|
-
`grandchildContext`) has access to the `answer` request decorator defined in
|
|
105
|
-
the _root context_.
|
|
102
|
+
`grandchildContext`) has access to the `answer` request decorator defined in
|
|
103
|
+
the _root context_.
|
|
106
104
|
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth`
|
|
107
|
-
plugin.
|
|
105
|
+
plugin.
|
|
108
106
|
3. Both the `publicContext` and `grandchildContext` have access to the `foo`
|
|
109
|
-
request decorator.
|
|
107
|
+
request decorator.
|
|
110
108
|
4. Only the `grandchildContext` has access to the `bar` request decorator.
|
|
111
109
|
|
|
112
110
|
To see this, start the server and issue requests:
|
|
@@ -125,16 +123,13 @@ To see this, start the server and issue requests:
|
|
|
125
123
|
## Sharing Between Contexts
|
|
126
124
|
<a id="shared-context"></a>
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
contexts
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
[fastify-plugin][fastify-plugin] such that anything registered in a descendent
|
|
133
|
-
context is available to the containing parent context.
|
|
126
|
+
Each context in the prior example inherits _only_ from its parent contexts. Parent
|
|
127
|
+
contexts cannot access entities within their descendant contexts. If needed,
|
|
128
|
+
encapsulation can be broken using [fastify-plugin][fastify-plugin], making
|
|
129
|
+
anything registered in a descendant context available to the parent context.
|
|
134
130
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
rewritten as:
|
|
131
|
+
To allow `publicContext` access to the `bar` decorator in `grandchildContext`,
|
|
132
|
+
rewrite the code as follows:
|
|
138
133
|
|
|
139
134
|
```js
|
|
140
135
|
'use strict'
|