fastify 2.4.1 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/SECURITY.md +33 -0
- package/build/build-validation.js +1 -1
- package/docs/Decorators.md +2 -2
- package/docs/Ecosystem.md +5 -1
- package/docs/Fluent-Schema.md +5 -7
- package/docs/Hooks.md +40 -40
- package/docs/Logging.md +15 -3
- package/docs/Plugins-Guide.md +21 -21
- package/docs/Plugins.md +11 -11
- package/docs/Reply.md +14 -7
- package/docs/Routes.md +6 -6
- package/docs/Server.md +40 -19
- package/docs/Serverless.md +127 -28
- package/docs/Validation-and-Serialization.md +15 -12
- package/fastify.d.ts +22 -14
- package/fastify.js +21 -0
- package/lib/context.js +5 -4
- package/lib/decorate.js +2 -0
- package/lib/errors.js +1 -0
- package/lib/handleRequest.js +2 -2
- package/lib/reply.js +23 -6
- package/lib/request.js +2 -2
- package/lib/route.js +24 -15
- package/lib/schemas.js +24 -3
- package/lib/symbols.js +1 -0
- package/lib/validation.js +19 -0
- package/package.json +19 -18
- package/test/async-await.js +1 -1
- package/test/close-pipelining.test.js +43 -2
- package/test/close.test.js +69 -12
- package/test/content-length.test.js +2 -2
- package/test/decorator.test.js +2 -0
- package/test/fluent-schema.js +54 -0
- package/test/hooks-async.js +80 -1
- package/test/hooks.test.js +4 -4
- package/test/http2/closing.js +86 -33
- package/test/input-validation.test.js +1 -1
- package/test/internals/decorator.test.js +2 -0
- package/test/internals/initialConfig.test.js +1 -1
- package/test/internals/reply.test.js +276 -1
- package/test/internals/validation.test.js +57 -0
- package/test/logger.test.js +33 -1
- package/test/nullable-validation.test.js +52 -0
- package/test/plugin.test.js +2 -0
- package/test/register.test.js +2 -0
- package/test/route-prefix.test.js +31 -0
- package/test/route.test.js +35 -0
- package/test/shared-schemas.test.js +3 -3
- package/test/types/index.ts +33 -2
- package/test/versioned-routes.test.js +3 -3
package/README.md
CHANGED
|
@@ -204,12 +204,12 @@ Team members are listed in alphabetical order.
|
|
|
204
204
|
### Collaborators
|
|
205
205
|
Great contributors on a specific area in the Fastify ecosystem will be invited to join this group by Lead Maintainers.
|
|
206
206
|
|
|
207
|
-
* [__Trivikram Kamat__](https://github.com/trivikr), <https://twitter.com/trivikram>, <https://www.npmjs.com/~trivikr>
|
|
208
207
|
* [__Luciano Mammino__](https://github.com/lmammino), <https://twitter.com/loige>, <https://www.npmjs.com/~lmammino>
|
|
209
208
|
* [__Evan Shortiss__](https://github.com/evanshortiss), <https://twitter.com/evanshortiss>, <https://www.npmjs.com/~evanshortiss>
|
|
210
209
|
|
|
211
210
|
**Past Collaborators**
|
|
212
211
|
* [__Çağatay Çalı__](https://github.com/cagataycali), <https://twitter.com/cagataycali>, <https://www.npmjs.com/~cagataycali>
|
|
212
|
+
* [__Trivikram Kamat__](https://github.com/trivikr), <https://twitter.com/trivikram>, <https://www.npmjs.com/~trivikr>
|
|
213
213
|
|
|
214
214
|
## Acknowledgements
|
|
215
215
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
This document describes the management of vulnerabilities for the Fastify project and it's officials' plugins.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Reporting vulnerabilities
|
|
7
|
+
|
|
8
|
+
Individuals who find potential vulnerabilities in Fastify are invited to complete a vulnerability report via the dedicated HackerOne tool for Node.js modules: [https://hackerone.com/nodejs-ecosystem](https://hackerone.com/nodejs-ecosystem).
|
|
9
|
+
|
|
10
|
+
### How to report a vulnerabiliy
|
|
11
|
+
|
|
12
|
+
It is of the utmost importance that you read carefully [**HOW TO REPORT A VULNERABILIY**](https://github.com/nodejs/security-wg/blob/master/processes/third_party_vuln_process.md) written by the Security Working Group of Node.js.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Handling vulnerability reports
|
|
16
|
+
|
|
17
|
+
When a potential vulnerability is reported and confirmed the Fastify Core Team will intervene in the
|
|
18
|
+
`follow-up` stage of the process following the workflow and the timings described in the Security WG's document.
|
|
19
|
+
|
|
20
|
+
### Vulnerabilities found outside this process
|
|
21
|
+
|
|
22
|
+
⚠ The Fastify project does not support any reporting outside the HackerOne process.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## The Fastify Core team
|
|
26
|
+
|
|
27
|
+
The core team is responsible for the management of [this](https://github.com/nodejs/security-wg/blob/master/processes/third_party_vuln_process.md#handling-vulnerability-reports) process.
|
|
28
|
+
|
|
29
|
+
Members of this team are expected to keep all information that they have privileged access to by being
|
|
30
|
+
on the team completely private to the team. This includes agreeing to not notify anyone outside the
|
|
31
|
+
team of issues that have not yet been disclosed publicly, including the existence of issues,
|
|
32
|
+
expectations of upcoming releases, and patching of any issues other than in the process of their work
|
|
33
|
+
as a member of the Fastify Core team.
|
|
@@ -72,7 +72,7 @@ const schema = {
|
|
|
72
72
|
|
|
73
73
|
const validate = ajv.compile(schema)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
|
|
76
76
|
/* istanbul ignore file */
|
|
77
77
|
// constant needed for customRule0 to work
|
|
78
78
|
const self = {}
|
package/docs/Decorators.md
CHANGED
|
@@ -137,9 +137,9 @@ As an example let's add a user property to the `Request` object:
|
|
|
137
137
|
fastify.decorateRequest('user', '')
|
|
138
138
|
|
|
139
139
|
// Update our property
|
|
140
|
-
fastify.addHook('preHandler', (req, reply,
|
|
140
|
+
fastify.addHook('preHandler', (req, reply, done) => {
|
|
141
141
|
req.user = 'Bob Dylan'
|
|
142
|
-
|
|
142
|
+
done()
|
|
143
143
|
})
|
|
144
144
|
// And finally access it
|
|
145
145
|
fastify.get('/', (req, reply) => {
|
package/docs/Ecosystem.md
CHANGED
|
@@ -47,7 +47,9 @@ Plugins maintained by the fastify team are listed under [Core](#core) while plug
|
|
|
47
47
|
|
|
48
48
|
- [`apollo-server-fastify`](https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-fastify) Run an [Apollo Server](https://github.com/apollographql/apollo-server) to serve GraphQL with Fastify.
|
|
49
49
|
- [`arecibo`](https://github.com/nucleode/arecibo) Fastify ping responder for Kubernetes Liveness and Readiness Probes.
|
|
50
|
+
- [`cls-rtracer`](https://github.com/puzpuzpuz/cls-rtracer) Fastify middleware for CLS-based request id generation. An out-of-the-box solution for adding request ids into your logs.
|
|
50
51
|
- [`fastify-405`](https://github.com/Eomm/fastify-405) Fastify plugin that adds 405 HTTP status to your routes
|
|
52
|
+
- [`fastify-amqp`](https://github.com/RafaelGSS/fastify-amqp) Fastify AMQP connection plugin, to use with RabbitMQ or another connector. Just a wrapper to [`amqplib`](https://github.com/squaremo/amqp.node).
|
|
51
53
|
- [`fastify-angular-universal`](https://github.com/exequiel09/fastify-angular-universal) Angular server-side rendering support using [`@angular/platform-server`](https://github.com/angular/angular/tree/master/packages/platform-server) for Fastify
|
|
52
54
|
- [`fastify-babel`](https://github.com/cfware/fastify-babel) Fastify plugin for development servers which require babel transformations of JavaScript sources.
|
|
53
55
|
- [`fastify-blipp`](https://github.com/PavelPolyakov/fastify-blipp) Prints your routes to the console, so you definitely know which endpoints are available.
|
|
@@ -88,16 +90,18 @@ Plugins maintained by the fastify team are listed under [Core](#core) while plug
|
|
|
88
90
|
- [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose) Fastify Mongoose plugin that connects to a MongoDB via the Mongoose plugin with support for Models.
|
|
89
91
|
- [`fastify-multer`](https://github.com/fox1t/multer) Multer is a plugin for handling multipart/form-data, which is primarily used for uploading files.
|
|
90
92
|
- [`fastify-nats`](https://github.com/mahmed8003/fastify-nats) Plugin to share [NATS](http://nats.io) client across Fastify.
|
|
93
|
+
- [`fastify-no-additional-properties`](https://github.com/greguz/fastify-no-additional-properties) Add `additionalProperties: false` by default to your JSON Schemas.
|
|
91
94
|
- [`fastify-no-icon`](https://github.com/jsumners/fastify-no-icon) Plugin to eliminate thrown errors for `/favicon.ico` requests.
|
|
92
95
|
- [`fastify-nodemailer`](https://github.com/lependu/fastify-nodemailer) Plugin to share [nodemailer](http://nodemailer.com) transporter across Fastify.
|
|
93
96
|
- [`fastify-normalize-request-reply`](https://github.com/ericrglass/fastify-normalize-request-reply) Plugin to normalize the request and reply to the Express version 4.x request and response, which allows use of middleware, like swagger-stats, that was originally written for Express.
|
|
94
|
-
- [`fastify-nuxt`](https://github.com/lyquocnam/fastify-nuxt) VueJS server side rendering support for Fastify with [`NuxtJS`](https://nuxtjs.org/)
|
|
95
97
|
- [`fastify-oas`](https://gitlab.com/m03geek/fastify-oas) Generates OpenAPI 3.0+ documentation from routes schemas for Fastify.
|
|
96
98
|
- [`fastify-openapi-glue`](https://github.com/seriousme/fastify-openapi-glue) Glue for Open Api specifications in Fastify, autogenerates routes based on an Open Api Specification
|
|
97
99
|
- [`fastify-oracle`](https://github.com/cemremengu/fastify-oracle) Attaches an [`oracledb`](https://github.com/oracle/node-oracledb) connection pool to a Fastify server instance.
|
|
98
100
|
- [`fastify-orientdb`](https://github.com/mahmed8003/fastify-orientdb) Fastify OrientDB connection plugin, with which you can share the OrientDB connection across every part of your server.
|
|
101
|
+
- [`fastify-rbac`](https://gitlab.com/m03geek/fastify-rbac) Fastify role-based access control plugin.
|
|
99
102
|
- [`fastify-register-routes`](https://github.com/israeleriston/fastify-register-routes) Plugin to automatically load routes from a specified path and optionally limit loaded file names by a regular expression.
|
|
100
103
|
- [`fastify-response-time`](https://github.com/lolo32/fastify-response-time) Add `X-Response-Time` header at each request for Fastify, in milliseconds.
|
|
104
|
+
- [`fastify-reverse-routes`](https://github.com/dimonnwc3/fastify-reverse-routes) Fastify reverse routes plugin, allows to defined named routes and build path using name and parameters.
|
|
101
105
|
- [`fastify-rob-config`](https://github.com/jeromemacias/fastify-rob-config) Fastify Rob-Config integration.
|
|
102
106
|
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint) Choose the JSON schema to use based on request parameters.
|
|
103
107
|
- [`fastify-sentry`](https://github.com/alex-ppg/fastify-sentry) Fastify plugin to add the Sentry SDK error handler to requests.
|
package/docs/Fluent-Schema.md
CHANGED
|
@@ -41,11 +41,12 @@ const paramsJsonSchema = S.object()
|
|
|
41
41
|
const headersJsonSchema = S.object()
|
|
42
42
|
.prop('x-foo', S.string().required())
|
|
43
43
|
|
|
44
|
+
// note that there is no need to call `.valueOf()`!
|
|
44
45
|
const schema = {
|
|
45
|
-
body: bodyJsonSchema
|
|
46
|
-
querystring: queryStringJsonSchema
|
|
47
|
-
params: paramsJsonSchema
|
|
48
|
-
headers: headersJsonSchema
|
|
46
|
+
body: bodyJsonSchema,
|
|
47
|
+
querystring: queryStringJsonSchema, // (or) query: queryStringJsonSchema
|
|
48
|
+
params: paramsJsonSchema,
|
|
49
|
+
headers: headersJsonSchema
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
fastify.post('/the/url', { schema }, handler)
|
|
@@ -69,20 +70,17 @@ const addressSchema = S.object()
|
|
|
69
70
|
.prop('country').required()
|
|
70
71
|
.prop('city').required()
|
|
71
72
|
.prop('zipcode').required()
|
|
72
|
-
.valueOf()
|
|
73
73
|
|
|
74
74
|
const commonSchemas = S.object()
|
|
75
75
|
.id('https://fastify/demo')
|
|
76
76
|
.definition('addressSchema', addressSchema)
|
|
77
77
|
.definition('otherSchema', otherSchema) // you can add any schemas you need
|
|
78
|
-
.valueOf()
|
|
79
78
|
|
|
80
79
|
fastify.addSchema(commonSchemas)
|
|
81
80
|
|
|
82
81
|
const bodyJsonSchema = S.object()
|
|
83
82
|
.prop('residence', S.ref('https://fastify/demo#address')).required()
|
|
84
83
|
.prop('office', S.ref('https://fastify/demo#/definitions/addressSchema')).required()
|
|
85
|
-
.valueOf()
|
|
86
84
|
|
|
87
85
|
const schema = { body: bodyJsonSchema }
|
|
88
86
|
|
package/docs/Hooks.md
CHANGED
|
@@ -18,44 +18,44 @@ By using the hooks you can interact directly inside the lifecycle of Fastify. Th
|
|
|
18
18
|
|
|
19
19
|
Example:
|
|
20
20
|
```js
|
|
21
|
-
fastify.addHook('onRequest', (request, reply,
|
|
21
|
+
fastify.addHook('onRequest', (request, reply, done) => {
|
|
22
22
|
// some code
|
|
23
|
-
|
|
23
|
+
done()
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
fastify.addHook('preParsing', (request, reply,
|
|
26
|
+
fastify.addHook('preParsing', (request, reply, done) => {
|
|
27
27
|
// some code
|
|
28
|
-
|
|
28
|
+
done()
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
fastify.addHook('preValidation', (request, reply,
|
|
31
|
+
fastify.addHook('preValidation', (request, reply, done) => {
|
|
32
32
|
// some code
|
|
33
|
-
|
|
33
|
+
done()
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
fastify.addHook('preHandler', (request, reply,
|
|
36
|
+
fastify.addHook('preHandler', (request, reply, done) => {
|
|
37
37
|
// some code
|
|
38
|
-
|
|
38
|
+
done()
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
fastify.addHook('preSerialization', (request, reply, payload,
|
|
41
|
+
fastify.addHook('preSerialization', (request, reply, payload, done) => {
|
|
42
42
|
// some code
|
|
43
|
-
|
|
43
|
+
done()
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
fastify.addHook('onError', (request, reply, error,
|
|
46
|
+
fastify.addHook('onError', (request, reply, error, done) => {
|
|
47
47
|
// some code
|
|
48
|
-
|
|
48
|
+
done()
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
fastify.addHook('onSend', (request, reply, payload,
|
|
51
|
+
fastify.addHook('onSend', (request, reply, payload, done) => {
|
|
52
52
|
// some code
|
|
53
|
-
|
|
53
|
+
done()
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
fastify.addHook('onResponse', (request, reply,
|
|
56
|
+
fastify.addHook('onResponse', (request, reply, done) => {
|
|
57
57
|
// some code
|
|
58
|
-
|
|
58
|
+
done()
|
|
59
59
|
})
|
|
60
60
|
```
|
|
61
61
|
Or `async/await`
|
|
@@ -136,29 +136,29 @@ fastify.addHook('onResponse', async (request, reply) => {
|
|
|
136
136
|
})
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
**Notice:** the `
|
|
139
|
+
**Notice:** the `done` callback is not available when using `async`/`await` or returning a `Promise`. If you do invoke a `done` callback in this situation unexpected behavior may occur, e.g. duplicate invocation of handlers.
|
|
140
140
|
|
|
141
141
|
**Notice:** in the `onRequest` and `preValidation` hooks, `request.body` will always be `null`, because the body parsing happens before the `preHandler` hook.
|
|
142
142
|
|
|
143
143
|
[Request](https://github.com/fastify/fastify/blob/master/docs/Request.md) and [Reply](https://github.com/fastify/fastify/blob/master/docs/Reply.md) are the core Fastify objects.<br/>
|
|
144
|
-
`
|
|
144
|
+
`done` is the function to continue with the [lifecycle](https://github.com/fastify/fastify/blob/master/docs/Lifecycle.md).
|
|
145
145
|
|
|
146
146
|
It is pretty easy to understand where each hook is executed by looking at the [lifecycle page](https://github.com/fastify/fastify/blob/master/docs/Lifecycle.md).<br>
|
|
147
147
|
Hooks are affected by Fastify's encapsulation, and can thus be applied to selected routes. See the [Scopes](#scope) section for more information.
|
|
148
148
|
|
|
149
|
-
If you get an error during the execution of your hook, just pass it to `
|
|
149
|
+
If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
|
|
150
150
|
|
|
151
151
|
```js
|
|
152
|
-
fastify.addHook('onRequest', (request, reply,
|
|
153
|
-
|
|
152
|
+
fastify.addHook('onRequest', (request, reply, done) => {
|
|
153
|
+
done(new Error('some error'))
|
|
154
154
|
})
|
|
155
155
|
```
|
|
156
156
|
|
|
157
157
|
If you want to pass a custom error code to the user, just use `reply.code()`:
|
|
158
158
|
```js
|
|
159
|
-
fastify.addHook('preHandler', (request, reply,
|
|
159
|
+
fastify.addHook('preHandler', (request, reply, done) => {
|
|
160
160
|
reply.code(400)
|
|
161
|
-
|
|
161
|
+
done(new Error('some error'))
|
|
162
162
|
})
|
|
163
163
|
```
|
|
164
164
|
|
|
@@ -169,13 +169,13 @@ fastify.addHook('preHandler', (request, reply, next) => {
|
|
|
169
169
|
This hook is useful if you need to do some custom error logging or add some specific header in case of error.<br/>
|
|
170
170
|
It is not intended for changing the error, and calling `reply.send` will throw an exception.<br/>
|
|
171
171
|
This hook will be executed only after the `customErrorHandler` has been executed, and only if the `customErrorHandler` sends back an error to the user *(Note that the default `customErrorHandler` always send back the error to the user)*.<br/>
|
|
172
|
-
**Notice:** unlike the other hooks, pass an error to the `
|
|
172
|
+
**Notice:** unlike the other hooks, pass an error to the `done` function is not supported.
|
|
173
173
|
|
|
174
174
|
```js
|
|
175
|
-
fastify.addHook('onError', (request, reply, error,
|
|
175
|
+
fastify.addHook('onError', (request, reply, error, done) => {
|
|
176
176
|
// apm stands for Application Performance Monitoring
|
|
177
177
|
apm.sendError(error)
|
|
178
|
-
|
|
178
|
+
done()
|
|
179
179
|
})
|
|
180
180
|
|
|
181
181
|
// Or async
|
|
@@ -190,10 +190,10 @@ fastify.addHook('onError', async (request, reply, error) => {
|
|
|
190
190
|
If you are using the `preSerialization` hook, you can change (or replace) the payload before it is serialized. For example:
|
|
191
191
|
|
|
192
192
|
```js
|
|
193
|
-
fastify.addHook('preSerialization', (request, reply, payload,
|
|
193
|
+
fastify.addHook('preSerialization', (request, reply, payload, done) => {
|
|
194
194
|
var err = null;
|
|
195
195
|
var newPayload = {wrapped: payload }
|
|
196
|
-
|
|
196
|
+
done(err, newPayload)
|
|
197
197
|
})
|
|
198
198
|
|
|
199
199
|
// Or async
|
|
@@ -209,10 +209,10 @@ Note: the hook is NOT called if the payload is a `string`, a `Buffer`, a `strea
|
|
|
209
209
|
If you are using the `onSend` hook, you can change the payload. For example:
|
|
210
210
|
|
|
211
211
|
```js
|
|
212
|
-
fastify.addHook('onSend', (request, reply, payload,
|
|
212
|
+
fastify.addHook('onSend', (request, reply, payload, done) => {
|
|
213
213
|
var err = null;
|
|
214
214
|
var newPayload = payload.replace('some-text', 'some-new-text')
|
|
215
|
-
|
|
215
|
+
done(err, newPayload)
|
|
216
216
|
})
|
|
217
217
|
|
|
218
218
|
// Or async
|
|
@@ -225,10 +225,10 @@ fastify.addHook('onSend', async (request, reply, payload) => {
|
|
|
225
225
|
You can also clear the payload to send a response with an empty body by replacing the payload with `null`:
|
|
226
226
|
|
|
227
227
|
```js
|
|
228
|
-
fastify.addHook('onSend', (request, reply, payload,
|
|
228
|
+
fastify.addHook('onSend', (request, reply, payload, done) => {
|
|
229
229
|
reply.code(304)
|
|
230
230
|
const newPayload = null
|
|
231
|
-
|
|
231
|
+
done(null, newPayload)
|
|
232
232
|
})
|
|
233
233
|
```
|
|
234
234
|
|
|
@@ -243,7 +243,7 @@ The `onResponse` hook is executed when a response has been sent, so you will not
|
|
|
243
243
|
If needed, you can respond to a request before you reach the route handler. An example could be an authentication hook. If you are using `onRequest` or `preHandler` use `reply.send`; if you are using a middleware, `res.end`.
|
|
244
244
|
|
|
245
245
|
```js
|
|
246
|
-
fastify.addHook('onRequest', (request, reply,
|
|
246
|
+
fastify.addHook('onRequest', (request, reply, done) => {
|
|
247
247
|
reply.send('early response')
|
|
248
248
|
})
|
|
249
249
|
|
|
@@ -256,7 +256,7 @@ fastify.addHook('preHandler', async (request, reply) => {
|
|
|
256
256
|
If you want to respond with a stream, you should avoid using an `async` function for the hook. If you must use an `async` function, your code will need to follow the pattern in [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275).
|
|
257
257
|
|
|
258
258
|
```js
|
|
259
|
-
fastify.addHook('onRequest', (request, reply,
|
|
259
|
+
fastify.addHook('onRequest', (request, reply, done) => {
|
|
260
260
|
const stream = fs.createReadStream('some-file', 'utf8')
|
|
261
261
|
reply.send(stream)
|
|
262
262
|
})
|
|
@@ -330,16 +330,16 @@ fastify.addHook('onRegister', (instance) => {
|
|
|
330
330
|
Except for [Application Hooks](#application-hooks), all hooks are encapsulated. This means that you can decide where your hooks should run by using `register` as explained in the [plugins guide](https://github.com/fastify/fastify/blob/master/docs/Plugins-Guide.md). If you pass a function, that function is bound to the right Fastify context and from there you have full access to the Fastify API.
|
|
331
331
|
|
|
332
332
|
```js
|
|
333
|
-
fastify.addHook('onRequest', function (request, reply,
|
|
333
|
+
fastify.addHook('onRequest', function (request, reply, done) {
|
|
334
334
|
const self = this // Fastify context
|
|
335
|
-
|
|
335
|
+
done()
|
|
336
336
|
})
|
|
337
337
|
```
|
|
338
338
|
Note: using an arrow function will break the binding of this to the Fastify instance.
|
|
339
339
|
|
|
340
340
|
<a name="route-hooks"></a>
|
|
341
341
|
## Route level hooks
|
|
342
|
-
You can declare one or more custom `onRequest`, `preParsing`, `preValidation`, `preHandler` and `preSerialization` hook(s) that will be unique for the route.
|
|
342
|
+
You can declare one or more custom `onRequest`, `preParsing`, `preValidation`, `preHandler` and `preSerialization` hook(s) that will be **unique** for the route.
|
|
343
343
|
If you do so, those hooks always be executed as last hook in their category. <br/>
|
|
344
344
|
This can be useful if you need to run the authentication, and the `preParsing` or `preValidation` hooks are exactly what you need for doing that.
|
|
345
345
|
Multiple route-level hooks can also be specified as an array.
|
|
@@ -367,7 +367,7 @@ fastify.addHook('preHandler', (request, reply, done) => {
|
|
|
367
367
|
done()
|
|
368
368
|
})
|
|
369
369
|
|
|
370
|
-
fastify.addHook('preSerialization', (request, reply, done) => {
|
|
370
|
+
fastify.addHook('preSerialization', (request, reply, payload, done) => {
|
|
371
371
|
// your code
|
|
372
372
|
done()
|
|
373
373
|
})
|
|
@@ -398,9 +398,9 @@ fastify.route({
|
|
|
398
398
|
// // this hook will always be executed after the shared `preHandler` hooks
|
|
399
399
|
// done()
|
|
400
400
|
// }],
|
|
401
|
-
preSerialization: (request, reply, payload,
|
|
401
|
+
preSerialization: (request, reply, payload, done) => {
|
|
402
402
|
// manipulate the payload
|
|
403
|
-
|
|
403
|
+
done(null, payload)
|
|
404
404
|
},
|
|
405
405
|
handler: function (request, reply) {
|
|
406
406
|
reply.send({ hello: 'world' })
|
package/docs/Logging.md
CHANGED
|
@@ -71,7 +71,7 @@ const fastify = require('fastify')({
|
|
|
71
71
|
}
|
|
72
72
|
})
|
|
73
73
|
```
|
|
74
|
-
For example, the response payload and headers could be logged using the approach below (even if it is *not
|
|
74
|
+
For example, the response payload and headers could be logged using the approach below (even if it is *not recommended*):
|
|
75
75
|
|
|
76
76
|
```js
|
|
77
77
|
const fastify = require('fastify')({
|
|
@@ -90,11 +90,10 @@ const fastify = require('fastify')({
|
|
|
90
90
|
url: req.url,
|
|
91
91
|
path: req.path,
|
|
92
92
|
parameters: req.parameters,
|
|
93
|
-
// Including the
|
|
93
|
+
// Including the headers in the log could be in violation
|
|
94
94
|
// of privacy laws, e.g. GDPR. You should use the "redact" option to
|
|
95
95
|
// remove sensitive fields. It could also leak authentication data in
|
|
96
96
|
// the logs.
|
|
97
|
-
body: req.body,
|
|
98
97
|
headers: req.headers
|
|
99
98
|
};
|
|
100
99
|
}
|
|
@@ -102,6 +101,19 @@ const fastify = require('fastify')({
|
|
|
102
101
|
}
|
|
103
102
|
});
|
|
104
103
|
```
|
|
104
|
+
**Note**: The body not can serialize inside `req` method, because the request is serialized when we create the child logger. At that time, the body is not parsed yet.
|
|
105
|
+
|
|
106
|
+
See a approach to log `req.body`
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
app.addHook('preHandler', function (req, reply, done) {
|
|
110
|
+
if (req.body) {
|
|
111
|
+
req.log.info({ body: req.body }, 'parsed body')
|
|
112
|
+
}
|
|
113
|
+
done()
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
105
117
|
|
|
106
118
|
*This option will be ignored by any logger other than Pino.*
|
|
107
119
|
|
package/docs/Plugins-Guide.md
CHANGED
|
@@ -35,20 +35,20 @@ Fastify helps you a lot in this direction, because thanks to the encapsulation m
|
|
|
35
35
|
*Let's return to how to correctly use `register`.*<br>
|
|
36
36
|
As you probably know, the required plugins must expose a single function with the following signature
|
|
37
37
|
```js
|
|
38
|
-
module.exports = function (fastify, options,
|
|
38
|
+
module.exports = function (fastify, options, done) {}
|
|
39
39
|
```
|
|
40
|
-
Where `fastify` is (pretty obvious) the encapsulated Fastify instance, `options` is the options object and `
|
|
40
|
+
Where `fastify` is (pretty obvious) the encapsulated Fastify instance, `options` is the options object and `done` is the function you **must** call when your plugin is ready.
|
|
41
41
|
|
|
42
42
|
Fastify's plugin model is fully reentrant and graph-based, it handles without any kind of problem asynchronous code and it guarantees the load order of the plugins, even the close order! *How?* Glad you asked, checkout [`avvio`](https://github.com/mcollina/avvio)! Fastify starts loading the plugin __after__ `.listen()`, `.inject()` or `.ready()` are called.
|
|
43
43
|
|
|
44
|
-
Inside a plugin you can do whatever you want, register routes, utilities (we'll see this in a moment) and do nested registers, just remember to call `
|
|
44
|
+
Inside a plugin you can do whatever you want, register routes, utilities (we'll see this in a moment) and do nested registers, just remember to call `done` when everything is set up!
|
|
45
45
|
```js
|
|
46
|
-
module.exports = function (fastify, options,
|
|
46
|
+
module.exports = function (fastify, options, done) {
|
|
47
47
|
fastify.get('/plugin', (request, reply) => {
|
|
48
48
|
reply.send({ hello: 'world' })
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
done()
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -77,38 +77,38 @@ fastify.decorate('util', (a, b) => a + b)
|
|
|
77
77
|
Now you can access your utility just by doing `fastify.util` whenever you need it, even inside your test.<br>
|
|
78
78
|
And here's starts the magic; do you remember that few lines above we talked about encapsulation? Well, using `register` and `decorate` in conjunction enable exactly that, let me show you an example to clarify this:
|
|
79
79
|
```js
|
|
80
|
-
fastify.register((instance, opts,
|
|
80
|
+
fastify.register((instance, opts, done) => {
|
|
81
81
|
instance.decorate('util', (a, b) => a + b)
|
|
82
82
|
console.log(instance.util('that is ', ' awesome'))
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
done()
|
|
85
85
|
})
|
|
86
86
|
|
|
87
|
-
fastify.register((instance, opts,
|
|
87
|
+
fastify.register((instance, opts, done) => {
|
|
88
88
|
console.log(instance.util('that is ', ' awesome')) // this will throw an error
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
done()
|
|
91
91
|
})
|
|
92
92
|
```
|
|
93
93
|
Inside the second register call `instance.util` will throw an error, because `util` exists only inside the first register context.<br>
|
|
94
94
|
Let's step back for a moment and get deeper on this: when using the `register` api you will create a new context every time and this avoids situations like the one mentioned few line above. But pay attention, the encapsulation works only for the ancestors and the brothers, but not for the sons.
|
|
95
95
|
```js
|
|
96
|
-
fastify.register((instance, opts,
|
|
96
|
+
fastify.register((instance, opts, done) => {
|
|
97
97
|
instance.decorate('util', (a, b) => a + b)
|
|
98
98
|
console.log(instance.util('that is ', ' awesome'))
|
|
99
99
|
|
|
100
|
-
fastify.register((instance, opts,
|
|
100
|
+
fastify.register((instance, opts, done) => {
|
|
101
101
|
console.log(instance.util('that is ', ' awesome')) // this will not throw an error
|
|
102
|
-
|
|
102
|
+
done()
|
|
103
103
|
})
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
done()
|
|
106
106
|
})
|
|
107
107
|
|
|
108
|
-
fastify.register((instance, opts,
|
|
108
|
+
fastify.register((instance, opts, done) => {
|
|
109
109
|
console.log(instance.util('that is ', ' awesome')) // this will throw an error
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
done()
|
|
112
112
|
})
|
|
113
113
|
```
|
|
114
114
|
*Take home message: if you need that an utility is available in every part of your application, pay attention that is declared at the root scope of your application. Otherwise you can use `fastify-plugin` utility as described [here](#distribution).*
|
|
@@ -214,7 +214,7 @@ Now for every request you will run your utility, it is obvious that you can regi
|
|
|
214
214
|
It can happen that you want a hook that must be executed just for a subset of routes, how can you do that? Yep, encapsulation!
|
|
215
215
|
|
|
216
216
|
```js
|
|
217
|
-
fastify.register((instance, opts,
|
|
217
|
+
fastify.register((instance, opts, done) => {
|
|
218
218
|
instance.decorate('util', (request, key, value) => { request[key] = value })
|
|
219
219
|
|
|
220
220
|
instance.addHook('preHandler', (request, reply, done) => {
|
|
@@ -226,7 +226,7 @@ fastify.register((instance, opts, next) => {
|
|
|
226
226
|
reply.send(request)
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
done()
|
|
230
230
|
})
|
|
231
231
|
|
|
232
232
|
fastify.get('/plugin2', (request, reply) => {
|
|
@@ -260,10 +260,10 @@ Yes, I said that. But what I didn't tell you, is that you can tell to Fastify to
|
|
|
260
260
|
const fp = require('fastify-plugin')
|
|
261
261
|
const dbClient = require('db-client')
|
|
262
262
|
|
|
263
|
-
function dbPlugin (fastify, opts,
|
|
263
|
+
function dbPlugin (fastify, opts, done) {
|
|
264
264
|
dbClient.connect(opts.url, (err, conn) => {
|
|
265
265
|
fastify.decorate('db', conn)
|
|
266
|
-
|
|
266
|
+
done()
|
|
267
267
|
})
|
|
268
268
|
}
|
|
269
269
|
|
|
@@ -279,10 +279,10 @@ const fastify = require('fastify')()
|
|
|
279
279
|
const fp = require('fastify-plugin')
|
|
280
280
|
const dbClient = require('db-client')
|
|
281
281
|
|
|
282
|
-
function dbPlugin (fastify, opts,
|
|
282
|
+
function dbPlugin (fastify, opts, done) {
|
|
283
283
|
dbClient.connect(opts.url, (err, conn) => {
|
|
284
284
|
fastify.decorate('db', conn)
|
|
285
|
-
|
|
285
|
+
done()
|
|
286
286
|
})
|
|
287
287
|
}
|
|
288
288
|
|
package/docs/Plugins.md
CHANGED
|
@@ -45,10 +45,10 @@ The `options` parameter can also be a `Function` which will be evaluated at the
|
|
|
45
45
|
```js
|
|
46
46
|
const fp = require('fastify-plugin')
|
|
47
47
|
|
|
48
|
-
fastify.register(fp((fastify, opts,
|
|
48
|
+
fastify.register(fp((fastify, opts, done) => {
|
|
49
49
|
fastify.decorate('foo_bar', { hello: 'world' })
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
done()
|
|
52
52
|
}))
|
|
53
53
|
|
|
54
54
|
// The opts argument of fastify-foo will be { hello: 'world' }
|
|
@@ -97,27 +97,27 @@ await fastify.listen(3000)
|
|
|
97
97
|
```
|
|
98
98
|
<a name="create-plugin"></a>
|
|
99
99
|
### Create a plugin
|
|
100
|
-
Creating a plugin is very easy, you just need to create a function that takes three parameters, the `fastify` instance, an options object and the
|
|
100
|
+
Creating a plugin is very easy, you just need to create a function that takes three parameters, the `fastify` instance, an `options` object and the `done` callback.<br>
|
|
101
101
|
Example:
|
|
102
102
|
```js
|
|
103
|
-
module.exports = function (fastify, opts,
|
|
103
|
+
module.exports = function (fastify, opts, done) {
|
|
104
104
|
fastify.decorate('utility', () => {})
|
|
105
105
|
|
|
106
106
|
fastify.get('/', handler)
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
done()
|
|
109
109
|
}
|
|
110
110
|
```
|
|
111
111
|
You can also use `register` inside another `register`:
|
|
112
112
|
```js
|
|
113
|
-
module.exports = function (fastify, opts,
|
|
113
|
+
module.exports = function (fastify, opts, done) {
|
|
114
114
|
fastify.decorate('utility', () => {})
|
|
115
115
|
|
|
116
116
|
fastify.get('/', handler)
|
|
117
117
|
|
|
118
118
|
fastify.register(require('./other-plugin'))
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
done()
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
Sometimes, you will need to know when the server is about to close, for example because you must close a connection to a database. To know when this is going to happen, you can use the [`'onClose'`](https://github.com/fastify/fastify/blob/master/docs/Hooks.md#on-close) hook.
|
|
@@ -136,18 +136,18 @@ We recommend to using the `fastify-plugin` module, because it solves this proble
|
|
|
136
136
|
```js
|
|
137
137
|
const fp = require('fastify-plugin')
|
|
138
138
|
|
|
139
|
-
module.exports = fp(function (fastify, opts,
|
|
139
|
+
module.exports = fp(function (fastify, opts, done) {
|
|
140
140
|
fastify.decorate('utility', () => {})
|
|
141
|
-
|
|
141
|
+
done()
|
|
142
142
|
}, '0.x')
|
|
143
143
|
```
|
|
144
144
|
Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin) documentation to know more about how use this module.
|
|
145
145
|
|
|
146
146
|
If you don't use the `fastify-plugin` module, you can use the `'skip-override'` hidden property, but we do not recommend it. If in the future the Fastify API changes it will be a your responsibility update the module, while if you use `fastify-plugin`, you can be sure about backwards compatibility.
|
|
147
147
|
```js
|
|
148
|
-
function yourPlugin (fastify, opts,
|
|
148
|
+
function yourPlugin (fastify, opts, done) {
|
|
149
149
|
fastify.decorate('utility', () => {})
|
|
150
|
-
|
|
150
|
+
done()
|
|
151
151
|
}
|
|
152
152
|
yourPlugin[Symbol.for('skip-override')] = true
|
|
153
153
|
module.exports = yourPlugin
|
package/docs/Reply.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- [.hasHeader(key)](#hasheaderkey)
|
|
11
11
|
- [.redirect(dest)](#redirectdest)
|
|
12
12
|
- [.callNotFound()](#callnotfound)
|
|
13
|
+
- [.getResponseTime()](#getresponsetime)
|
|
13
14
|
- [.type(contentType)](#typecontenttype)
|
|
14
15
|
- [.serializer(func)](#serializerfunc)
|
|
15
16
|
- [.sent](#sent)
|
|
@@ -109,6 +110,14 @@ Invokes the custom not found handler.
|
|
|
109
110
|
reply.callNotFound()
|
|
110
111
|
```
|
|
111
112
|
|
|
113
|
+
<a name="getResponseTime"></a>
|
|
114
|
+
### .getResponseTime()
|
|
115
|
+
Invokes the custom response time getter to calculate the amount of time passed since the request was started.
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
const milliseconds = reply.getResponseTime()
|
|
119
|
+
```
|
|
120
|
+
|
|
112
121
|
<a name="type"></a>
|
|
113
122
|
### .type(contentType)
|
|
114
123
|
Sets the content type for the response.
|
|
@@ -274,17 +283,15 @@ The type of the sent payload (after serialization and going through any [`onSend
|
|
|
274
283
|
Fastify natively handles promises and supports async-await.<br>
|
|
275
284
|
*Note that in the following examples we are not using reply.send.*
|
|
276
285
|
```js
|
|
286
|
+
const delay = promisify(setTimeout)
|
|
287
|
+
|
|
277
288
|
fastify.get('/promises', options, function (request, reply) {
|
|
278
|
-
|
|
279
|
-
setTimeout(resolve, 200, { hello: 'world' })
|
|
280
|
-
})
|
|
289
|
+
return delay(200).then(() => { return { hello: 'world' }})
|
|
281
290
|
})
|
|
282
291
|
|
|
283
292
|
fastify.get('/async-await', options, async function (request, reply) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
})
|
|
287
|
-
return res
|
|
293
|
+
await delay(200)
|
|
294
|
+
return { hello: 'world' }
|
|
288
295
|
})
|
|
289
296
|
```
|
|
290
297
|
|