fastify 5.2.1 → 5.2.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/LICENSE +1 -1
- package/PROJECT_CHARTER.md +7 -7
- package/README.md +24 -25
- package/SPONSORS.md +2 -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 +5 -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 +50 -60
- package/docs/Reference/Encapsulation.md +28 -33
- package/docs/Reference/Errors.md +50 -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 +1 -1
- package/lib/contentTypeParser.js +7 -8
- package/lib/error-handler.js +14 -12
- package/lib/headRoute.js +4 -2
- package/lib/pluginUtils.js +4 -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 +10 -10
- package/test/build/error-serializer.test.js +2 -1
- 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/genReqId.test.js +125 -174
- package/test/has-route.test.js +1 -3
- package/test/internals/content-type-parser.test.js +1 -1
- package/test/issue-4959.test.js +84 -0
- package/test/listen.1.test.js +37 -34
- package/test/listen.2.test.js +47 -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/server.test.js +0 -175
- 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 +1 -0
- package/test/upgrade.test.js +32 -30
- package/types/instance.d.ts +4 -0
package/docs/Guides/Testing.md
CHANGED
|
@@ -340,10 +340,10 @@ test('should ...', {only: true}, t => ...)
|
|
|
340
340
|
```
|
|
341
341
|
2. Run `node --test`
|
|
342
342
|
```bash
|
|
343
|
-
> node --test --test-only --
|
|
343
|
+
> node --test --test-only --inspect-brk test/<test-file.test.js>
|
|
344
344
|
```
|
|
345
345
|
- `--test-only` specifies to run tests with the `only` option enabled
|
|
346
|
-
- `--
|
|
346
|
+
- `--inspect-brk` will launch the node debugger
|
|
347
347
|
3. In VS Code, create and launch a `Node.js: Attach` debug configuration. No
|
|
348
348
|
modification should be necessary.
|
|
349
349
|
|
|
@@ -14,7 +14,7 @@ suggestion"](https://github.com/fastify/fastify/issues?q=is%3Aissue+is%3Aopen+la
|
|
|
14
14
|
in our issue tracker!*
|
|
15
15
|
|
|
16
16
|
## Code
|
|
17
|
-
Fastify uses different techniques to optimize its code, many of
|
|
17
|
+
Fastify uses different techniques to optimize its code, many of which are
|
|
18
18
|
documented in our Guides. We highly recommend you read [the hitchhiker's guide
|
|
19
19
|
to plugins](./Plugins-Guide.md) to discover all the APIs you can use to build
|
|
20
20
|
your plugin and learn how to use them.
|
|
@@ -53,8 +53,7 @@ Always put an example file in your repository. Examples are very helpful for
|
|
|
53
53
|
users and give a very fast way to test your plugin. Your users will be grateful.
|
|
54
54
|
|
|
55
55
|
## Test
|
|
56
|
-
|
|
57
|
-
working properly.
|
|
56
|
+
A plugin **must** be thoroughly tested to verify that is working properly.
|
|
58
57
|
|
|
59
58
|
A plugin without tests will not be accepted to the ecosystem list. A lack of
|
|
60
59
|
tests does not inspire trust nor guarantee that the code will continue to work
|
|
@@ -1,38 +1,32 @@
|
|
|
1
1
|
<h1 align="center">Fastify</h1>
|
|
2
2
|
|
|
3
3
|
## `Content-Type` Parser
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Other common content types are supported through the use of
|
|
8
|
-
[plugins](https://fastify.dev/ecosystem/).
|
|
4
|
+
Fastify natively supports `'application/json'` and `'text/plain'` content types
|
|
5
|
+
with a default charset of `utf-8`. These default parsers can be changed or
|
|
6
|
+
removed.
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
you can use the `addContentTypeParser` API. *The default JSON and/or plain text
|
|
12
|
-
parser can be changed or removed.*
|
|
8
|
+
Unsupported content types will throw an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error.
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
`text/html; charset=utf-8`.*
|
|
10
|
+
To support other content types, use the `addContentTypeParser` API or an
|
|
11
|
+
existing [plugin](https://fastify.dev/ecosystem/).
|
|
17
12
|
|
|
18
|
-
As with
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
available only in that scope and its children.
|
|
13
|
+
As with other APIs, `addContentTypeParser` is encapsulated in the scope in which
|
|
14
|
+
it is declared. If declared in the root scope, it is available everywhere; if
|
|
15
|
+
declared in a plugin, it is available only in that scope and its children.
|
|
22
16
|
|
|
23
17
|
Fastify automatically adds the parsed request payload to the [Fastify
|
|
24
|
-
request](./Request.md) object
|
|
25
|
-
|
|
26
|
-
Note that for `GET` and `HEAD` requests the payload is never parsed. For
|
|
27
|
-
`OPTIONS` and `DELETE` requests the payload is only
|
|
28
|
-
|
|
29
|
-
[catch-all](#catch-all) parser is not executed
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
>
|
|
33
|
-
> When using
|
|
34
|
-
>
|
|
35
|
-
>
|
|
18
|
+
request](./Request.md) object, accessible via `request.body`.
|
|
19
|
+
|
|
20
|
+
Note that for `GET` and `HEAD` requests, the payload is never parsed. For
|
|
21
|
+
`OPTIONS` and `DELETE` requests, the payload is parsed only if a valid
|
|
22
|
+
`content-type` header is provided. Unlike `POST`, `PUT`, and `PATCH`, the
|
|
23
|
+
[catch-all](#catch-all) parser is not executed, and the payload is simply not
|
|
24
|
+
parsed.
|
|
25
|
+
|
|
26
|
+
> ⚠ Warning:
|
|
27
|
+
> When using regular expressions to detect `Content-Type`, it is important to
|
|
28
|
+
> ensure proper detection. For example, to match `application/*`, use
|
|
29
|
+
> `/^application\/([\w-]+);?/` to match the
|
|
36
30
|
> [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
|
|
37
31
|
> only.
|
|
38
32
|
|
|
@@ -70,11 +64,10 @@ fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefa
|
|
|
70
64
|
```
|
|
71
65
|
|
|
72
66
|
Fastify first tries to match a content-type parser with a `string` value before
|
|
73
|
-
trying to find a matching `RegExp`.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
more specific one, like in the example below.
|
|
67
|
+
trying to find a matching `RegExp`. For overlapping content types, it starts
|
|
68
|
+
with the last one configured and ends with the first (last in, first out).
|
|
69
|
+
To specify a general content type more precisely, first specify the general
|
|
70
|
+
type, then the specific one, as shown below.
|
|
78
71
|
|
|
79
72
|
```js
|
|
80
73
|
// Here only the second content type parser is called because its value also matches the first one
|
|
@@ -88,10 +81,9 @@ fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done)
|
|
|
88
81
|
```
|
|
89
82
|
|
|
90
83
|
### Using addContentTypeParser with fastify.register
|
|
91
|
-
When using `addContentTypeParser`
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
before the addContentTypeParser has been set.
|
|
84
|
+
When using `addContentTypeParser` with `fastify.register`, avoid `await`
|
|
85
|
+
when registering routes. Using `await` makes route registration asynchronous,
|
|
86
|
+
potentially registering routes before `addContentTypeParser` is set.
|
|
95
87
|
|
|
96
88
|
#### Correct Usage
|
|
97
89
|
```js
|
|
@@ -109,14 +101,13 @@ fastify.register((fastify, opts) => {
|
|
|
109
101
|
});
|
|
110
102
|
```
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
`removeAllContentTypeParsers`.
|
|
104
|
+
In addition to `addContentTypeParser`, the `hasContentTypeParser`,
|
|
105
|
+
`removeContentTypeParser`, and `removeAllContentTypeParsers` APIs are available.
|
|
115
106
|
|
|
116
107
|
#### hasContentTypeParser
|
|
117
108
|
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
Use the `hasContentTypeParser` API to check if a specific content type parser
|
|
110
|
+
exists.
|
|
120
111
|
|
|
121
112
|
```js
|
|
122
113
|
if (!fastify.hasContentTypeParser('application/jsoff')){
|
|
@@ -130,8 +121,8 @@ if (!fastify.hasContentTypeParser('application/jsoff')){
|
|
|
130
121
|
|
|
131
122
|
#### removeContentTypeParser
|
|
132
123
|
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
`removeContentTypeParser` can remove a single content type or an array of
|
|
125
|
+
content types, supporting both `string` and `RegExp`.
|
|
135
126
|
|
|
136
127
|
```js
|
|
137
128
|
fastify.addContentTypeParser('text/xml', function (request, payload, done) {
|
|
@@ -145,16 +136,11 @@ fastify.removeContentTypeParser(['application/json', 'text/plain'])
|
|
|
145
136
|
```
|
|
146
137
|
|
|
147
138
|
#### removeAllContentTypeParsers
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
the example above except that we do not need to specify each content type to
|
|
154
|
-
delete. Just like `removeContentTypeParser`, this API supports encapsulation.
|
|
155
|
-
The API is especially useful if you want to register a [catch-all content type
|
|
156
|
-
parser](#catch-all) that should be executed for every content type and the
|
|
157
|
-
built-in parsers should be ignored as well.
|
|
139
|
+
The `removeAllContentTypeParsers` API removes all existing content type parsers
|
|
140
|
+
eliminating the need to specify each one individually. This API supports
|
|
141
|
+
encapsulation and is useful for registering a
|
|
142
|
+
[catch-all content type parser](#catch-all) that should be executed for every
|
|
143
|
+
content type, ignoring built-in parsers.
|
|
158
144
|
|
|
159
145
|
```js
|
|
160
146
|
fastify.removeAllContentTypeParsers()
|
|
@@ -166,18 +152,16 @@ fastify.addContentTypeParser('text/xml', function (request, payload, done) {
|
|
|
166
152
|
})
|
|
167
153
|
```
|
|
168
154
|
|
|
169
|
-
|
|
170
|
-
|
|
155
|
+
> 🛈 Note: `function(req, done)` and `async function(req)` are
|
|
156
|
+
> still supported but deprecated.
|
|
171
157
|
|
|
172
158
|
#### Body Parser
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
size](./Server.md#factory-body-limit) of the body and the content length. If the
|
|
180
|
-
limit is exceeded the custom parser will not be invoked.
|
|
159
|
+
The request body can be parsed in two ways. First, add a custom content type
|
|
160
|
+
parser and handle the request stream. Or second, use the `parseAs` option in the
|
|
161
|
+
`addContentTypeParser` API, specifying `'string'` or `'buffer'`. Fastify will
|
|
162
|
+
handle the stream, check the [maximum size](./Server.md#factory-body-limit) of
|
|
163
|
+
the body, and the content length. If the limit is exceeded, the custom parser
|
|
164
|
+
will not be invoked.
|
|
181
165
|
```js
|
|
182
166
|
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
|
|
183
167
|
try {
|
|
@@ -195,15 +179,14 @@ See
|
|
|
195
179
|
for an example.
|
|
196
180
|
|
|
197
181
|
##### Custom Parser Options
|
|
198
|
-
+ `parseAs` (string):
|
|
199
|
-
|
|
182
|
+
+ `parseAs` (string): `'string'` or `'buffer'` to designate how the incoming
|
|
183
|
+
data should be collected. Default: `'buffer'`.
|
|
200
184
|
+ `bodyLimit` (number): The maximum payload size, in bytes, that the custom
|
|
201
185
|
parser will accept. Defaults to the global body limit passed to the [`Fastify
|
|
202
186
|
factory function`](./Server.md#bodylimit).
|
|
203
187
|
|
|
204
188
|
#### Catch-All
|
|
205
|
-
|
|
206
|
-
content type. With Fastify, you can just use the `'*'` content type.
|
|
189
|
+
To catch all requests regardless of content type, use the `'*'` content type:
|
|
207
190
|
```js
|
|
208
191
|
fastify.addContentTypeParser('*', function (request, payload, done) {
|
|
209
192
|
let data = ''
|
|
@@ -213,12 +196,10 @@ fastify.addContentTypeParser('*', function (request, payload, done) {
|
|
|
213
196
|
})
|
|
214
197
|
})
|
|
215
198
|
```
|
|
199
|
+
All requests without a corresponding content type parser will be handled by
|
|
200
|
+
this function.
|
|
216
201
|
|
|
217
|
-
|
|
218
|
-
will be handled by the specified function.
|
|
219
|
-
|
|
220
|
-
This is also useful for piping the request stream. You can define a content
|
|
221
|
-
parser like:
|
|
202
|
+
This is also useful for piping the request stream. Define a content parser like:
|
|
222
203
|
|
|
223
204
|
```js
|
|
224
205
|
fastify.addContentTypeParser('*', function (request, payload, done) {
|
|
@@ -226,7 +207,7 @@ fastify.addContentTypeParser('*', function (request, payload, done) {
|
|
|
226
207
|
})
|
|
227
208
|
```
|
|
228
209
|
|
|
229
|
-
|
|
210
|
+
And then access the core HTTP request directly for piping:
|
|
230
211
|
|
|
231
212
|
```js
|
|
232
213
|
app.post('/hello', (request, reply) => {
|
|
@@ -254,12 +235,11 @@ fastify.route({
|
|
|
254
235
|
})
|
|
255
236
|
```
|
|
256
237
|
|
|
257
|
-
For piping file uploads
|
|
258
|
-
|
|
238
|
+
For piping file uploads, check out
|
|
239
|
+
[`@fastify/multipart`](https://github.com/fastify/fastify-multipart).
|
|
259
240
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`removeAllContentTypeParsers` method first.
|
|
241
|
+
To execute the content type parser on all content types, call
|
|
242
|
+
`removeAllContentTypeParsers` first.
|
|
263
243
|
|
|
264
244
|
```js
|
|
265
245
|
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parser
|
|
@@ -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', {
|
|
@@ -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'
|