fastify 5.0.0-alpha.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/docs/Guides/Getting-Started.md +3 -3
- package/docs/Guides/Migration-Guide-V4.md +12 -8
- package/docs/Guides/Migration-Guide-V5.md +569 -1
- package/docs/Reference/LTS.md +6 -5
- package/fastify.js +2 -2
- package/lib/warnings.js +2 -0
- package/package.json +2 -2
- package/test/close.test.js +4 -1
- package/test/hooks.test.js +3 -2
- package/test/types/hooks.test-d.ts +5 -6
- package/test/types/instance.test-d.ts +12 -10
- package/types/hooks.d.ts +4 -3
package/README.md
CHANGED
|
@@ -346,6 +346,10 @@ listed in alphabetical order.
|
|
|
346
346
|
<https://twitter.com/simonebu>, <https://www.npmjs.com/~simoneb>
|
|
347
347
|
* [__Gürgün Dayıoğlu__](https://github.com/gurgunday),
|
|
348
348
|
<https://www.npmjs.com/~gurgunday>
|
|
349
|
+
* [__Dan Castillo__](https://github.com/dancastillo),
|
|
350
|
+
<https://www.npmjs.com/~dancastillo>
|
|
351
|
+
* [__Jean Michelet__](https://github.com/jean-michelet),
|
|
352
|
+
<https://www.npmjs.com/~jean-michelet>
|
|
349
353
|
|
|
350
354
|
### Great Contributors
|
|
351
355
|
Great contributors on a specific area in the Fastify ecosystem will be invited
|
|
@@ -143,7 +143,7 @@ declaration](../Reference/Routes.md) docs).
|
|
|
143
143
|
```js
|
|
144
144
|
// ESM
|
|
145
145
|
import Fastify from 'fastify'
|
|
146
|
-
import firstRoute from './our-first-route'
|
|
146
|
+
import firstRoute from './our-first-route.js'
|
|
147
147
|
/**
|
|
148
148
|
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
149
149
|
*/
|
|
@@ -232,8 +232,8 @@ npm i fastify-plugin @fastify/mongodb
|
|
|
232
232
|
```js
|
|
233
233
|
// ESM
|
|
234
234
|
import Fastify from 'fastify'
|
|
235
|
-
import dbConnector from './our-db-connector'
|
|
236
|
-
import firstRoute from './our-first-route'
|
|
235
|
+
import dbConnector from './our-db-connector.js'
|
|
236
|
+
import firstRoute from './our-first-route.js'
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
239
|
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
@@ -9,25 +9,29 @@ work after upgrading.
|
|
|
9
9
|
## Codemods
|
|
10
10
|
### Fastify v4 Codemods
|
|
11
11
|
|
|
12
|
-
To help with the upgrade, we’ve worked with the team at
|
|
12
|
+
To help with the upgrade, we’ve worked with the team at
|
|
13
|
+
[Codemod](https://github.com/codemod-com/codemod) to
|
|
13
14
|
publish codemods that will automatically update your code to many of
|
|
14
15
|
the new APIs and patterns in Fastify v4.
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
Run the following
|
|
18
|
+
[migration recipe](https://go.codemod.com/fastify-4-migration-recipe) to
|
|
19
|
+
automatically update your code to Fastify v4:
|
|
16
20
|
|
|
17
21
|
```
|
|
18
22
|
npx codemod@latest fastify/4/migration-recipe
|
|
19
23
|
```
|
|
20
24
|
|
|
21
|
-
This will run the following codemods
|
|
25
|
+
This will run the following codemods:
|
|
22
26
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
+
- [`fastify/4/remove-app-use`](https://go.codemod.com/fastify-4-remove-app-use)
|
|
28
|
+
- [`fastify/4/reply-raw-access`](https://go.codemod.com/fastify-4-reply-raw-access)
|
|
29
|
+
- [`fastify/4/wrap-routes-plugin`](https://go.codemod.com/fastify-4-wrap-routes-plugin)
|
|
30
|
+
- [`fastify/4/await-register-calls`](https://go.codemod.com/fastify-4-await-register-calls)
|
|
27
31
|
|
|
28
32
|
Each of these codemods automates the changes listed in the v4 migration guide.
|
|
29
33
|
For a complete list of available Fastify codemods and further details,
|
|
30
|
-
see
|
|
34
|
+
see [Codemod Registry](https://go.codemod.com/fastify).
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
## Breaking Changes
|
|
@@ -3,11 +3,103 @@
|
|
|
3
3
|
This guide is intended to help with migration from Fastify v4 to v5.
|
|
4
4
|
|
|
5
5
|
Before migrating to v5, please ensure that you have fixed all deprecation
|
|
6
|
-
warnings from v4. All v4 deprecations have been removed and
|
|
6
|
+
warnings from v4. All v4 deprecations have been removed and will no longer
|
|
7
7
|
work after upgrading.
|
|
8
8
|
|
|
9
|
+
## Long Term Support Cycle
|
|
10
|
+
|
|
11
|
+
Fastify v5 will only support Node.js v20+. If you are using an older version of
|
|
12
|
+
Node.js, you will need to upgrade to a newer version to use Fastify v5.
|
|
13
|
+
|
|
14
|
+
Fastify v4 is still supported until June 30, 2025. If you are unable to upgrade,
|
|
15
|
+
you should consider buying an end-of-life support plan from HeroDevs.
|
|
16
|
+
|
|
17
|
+
### Why Node.js v20?
|
|
18
|
+
|
|
19
|
+
Fastify v5 will only support Node.js v20+ because it has significant differences
|
|
20
|
+
compared to v18, such as
|
|
21
|
+
better support for `node:test`. This allows us to provide a better developer
|
|
22
|
+
experience and streamline maintenance.
|
|
23
|
+
|
|
24
|
+
Node.js v18 will exit Long Term Support on April 30, 2025, so you should be planning
|
|
25
|
+
to upgrade to v20 anyway.
|
|
26
|
+
|
|
9
27
|
## Breaking Changes
|
|
10
28
|
|
|
29
|
+
### Full JSON Schema is now required for `querystring`, `params` and `body` and response schemas
|
|
30
|
+
|
|
31
|
+
Starting with v5, Fastify will require a full JSON schema for the `querystring`,
|
|
32
|
+
`params` and `body` schema. Note that the `jsonShortHand` option has been
|
|
33
|
+
removed as well.
|
|
34
|
+
|
|
35
|
+
If the default JSON Schema validator is used, you will need
|
|
36
|
+
to provide a full JSON schema for the
|
|
37
|
+
`querystring`, `params`, `body`, and `response` schemas,
|
|
38
|
+
including the `type` property.
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
// v4
|
|
42
|
+
fastify.get('/route', {
|
|
43
|
+
schema: {
|
|
44
|
+
querystring: {
|
|
45
|
+
name: { type: 'string' }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, (req, reply) => {
|
|
49
|
+
reply.send({ hello: req.query.name });
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
// v5
|
|
55
|
+
fastify.get('/route', {
|
|
56
|
+
schema: {
|
|
57
|
+
querystring: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
name: { type: 'string' }
|
|
61
|
+
},
|
|
62
|
+
required: ['name']
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, (req, reply) => {
|
|
66
|
+
reply.send({ hello: req.query.name });
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See [#5586](https://github.com/fastify/fastify/pull/5586) for more details
|
|
71
|
+
|
|
72
|
+
Note that it's still possible to override the JSON Schema validator to
|
|
73
|
+
use a different format, such as Zod. This change simplifies that as well.
|
|
74
|
+
|
|
75
|
+
This change helps with integration of other tools, such as
|
|
76
|
+
[`@fastify/swagger`](https://github.com/fastify/fastify-swagger).
|
|
77
|
+
|
|
78
|
+
### New logger constructor signature
|
|
79
|
+
|
|
80
|
+
In Fastify v4, Fastify accepted the options to build a pino
|
|
81
|
+
logger in the `logger` option, as well as a custom logger instance.
|
|
82
|
+
This was the source of significant confusion.
|
|
83
|
+
|
|
84
|
+
As a result, the `logger` option will not accept a custom logger anymore in v5.
|
|
85
|
+
To use a custom logger, you should use the `loggerInstance` option instead:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// v4
|
|
89
|
+
const logger = require('pino')();
|
|
90
|
+
const fastify = require('fastify')({
|
|
91
|
+
logger
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// v5
|
|
97
|
+
const loggerInstance = require('pino')();
|
|
98
|
+
const fastify = require('fastify')({
|
|
99
|
+
loggerInstance
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
11
103
|
### `useSemicolonDelimiter` false by default
|
|
12
104
|
|
|
13
105
|
Starting with v5, Fastify instances will no longer default to supporting the use
|
|
@@ -18,3 +110,479 @@ behavior and not adhering to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#s
|
|
|
18
110
|
If you still wish to use semicolons as delimiters, you can do so by
|
|
19
111
|
setting `useSemicolonDelimiter: true` in the server configuration.
|
|
20
112
|
|
|
113
|
+
```js
|
|
114
|
+
const fastify = require('fastify')({
|
|
115
|
+
useSemicolonDelimiter: true
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### The parameters object no longer has a prototype
|
|
120
|
+
|
|
121
|
+
In v4, the `parameters` object had a prototype. This is no longer the case in v5.
|
|
122
|
+
This means that you can no longer access properties inherited from `Object` on
|
|
123
|
+
the `parameters` object, such as `toString` or `hasOwnProperty`.
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
// v4
|
|
127
|
+
fastify.get('/route/:name', (req, reply) => {
|
|
128
|
+
console.log(req.params.hasOwnProperty('name')); // true
|
|
129
|
+
return { hello: req.params.name };
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
// v5
|
|
135
|
+
fastify.get('/route/:name', (req, reply) => {
|
|
136
|
+
console.log(Object.hasOwn(req.params, 'name')); // true
|
|
137
|
+
return { hello: req.params.name };
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This increases the security of the application by hardening against prototype
|
|
142
|
+
pollution attacks.
|
|
143
|
+
|
|
144
|
+
### Type Providers now differentiate between validator and serializer schemas
|
|
145
|
+
|
|
146
|
+
In v4, the type providers had the same types for both validation and serialization.
|
|
147
|
+
In v5, the type providers have been split into two separate types: `ValidatorSchema`
|
|
148
|
+
and `SerializerSchema`.
|
|
149
|
+
|
|
150
|
+
[`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
|
|
151
|
+
and
|
|
152
|
+
[`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
|
|
153
|
+
have already been updated: upgrade to the latest version to get the new types.
|
|
154
|
+
If you are using a custom type provider, you will need to modify it like
|
|
155
|
+
the following:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
--- a/index.ts
|
|
159
|
+
+++ b/index.ts
|
|
160
|
+
@@ -11,7 +11,8 @@ import {
|
|
161
|
+
import { FromSchema, FromSchemaDefaultOptions, FromSchemaOptions, JSONSchema } from 'json-schema-to-ts'
|
|
162
|
+
|
|
163
|
+
export interface JsonSchemaToTsProvider<
|
|
164
|
+
Options extends FromSchemaOptions = FromSchemaDefaultOptions
|
|
165
|
+
> extends FastifyTypeProvider {
|
|
166
|
+
- output: this['input'] extends JSONSchema ? FromSchema<this['input'], Options> : unknown;
|
|
167
|
+
+ validator: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
|
|
168
|
+
+ serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Changes to the .listen() method
|
|
173
|
+
|
|
174
|
+
The variadic argument signature of the `.listen()` method has been removed.
|
|
175
|
+
This means that you can no longer call `.listen()` with a variable number of arguments.
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
// v4
|
|
179
|
+
fastify.listen(8000)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Will become:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
// v5
|
|
186
|
+
fastify.listen({ port: 8000 })
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
This was already deprecated in v4 as `FSTDEP011`, so you should have already updated
|
|
190
|
+
your code to use the new signature.
|
|
191
|
+
|
|
192
|
+
### Direct return of trailers has been removed
|
|
193
|
+
|
|
194
|
+
In v4, you could directly return trailers from a handler.
|
|
195
|
+
This is no longer possible in v5.
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
// v4
|
|
199
|
+
fastify.get('/route', (req, reply) => {
|
|
200
|
+
reply.trailer('ETag', function (reply, payload) {
|
|
201
|
+
return 'custom-etag'
|
|
202
|
+
})
|
|
203
|
+
reply.send('')
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
// v5
|
|
209
|
+
fastify.get('/route', (req, reply) => {
|
|
210
|
+
reply.trailer('ETag', async function (reply, payload) {
|
|
211
|
+
return 'custom-etag'
|
|
212
|
+
})
|
|
213
|
+
reply.send('')
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
A callback could also be used.
|
|
218
|
+
This was already deprecated in v4 as `FSTDEP013`,
|
|
219
|
+
so you should have already updated your code to use the new signature.
|
|
220
|
+
|
|
221
|
+
### Streamlined access to route definition
|
|
222
|
+
|
|
223
|
+
All deprecated properties relating to accessing the route definition have been removed
|
|
224
|
+
and are now accessed via `request.routeOptions`.
|
|
225
|
+
|
|
226
|
+
| Code | Description | How to solve | Discussion |
|
|
227
|
+
| ---- | ----------- | ------------ | ---------- |
|
|
228
|
+
| FSTDEP012 | You are trying to access the deprecated `request.context` property. | Use `request.routeOptions.config` or `request.routeOptions.schema`. | [#4216](https://github.com/fastify/fastify/pull/4216) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
|
229
|
+
| FSTDEP015 | You are accessing the deprecated `request.routeSchema` property. | Use `request.routeOptions.schema`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
|
230
|
+
| FSTDEP016 | You are accessing the deprecated `request.routeConfig` property. | Use `request.routeOptions.config`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
|
231
|
+
| FSTDEP017 | You are accessing the deprecated `request.routerPath` property. | Use `request.routeOptions.url`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
|
232
|
+
| FSTDEP018 | You are accessing the deprecated `request.routerMethod` property. | Use `request.routeOptions.method`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
|
233
|
+
| FSTDEP019 | You are accessing the deprecated `reply.context` property. | Use `reply.routeOptions.config` or `reply.routeOptions.schema`. | [#5032](https://github.com/fastify/fastify/pull/5032) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
|
234
|
+
|
|
235
|
+
See [#5616](https://github.com/fastify/fastify/pull/5616) for more information.
|
|
236
|
+
|
|
237
|
+
### `reply.redirect()` has a new signature
|
|
238
|
+
|
|
239
|
+
The `reply.redirect()` method has a new signature:
|
|
240
|
+
`reply.redirect(url: string, code?: number)`.
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
// v4
|
|
244
|
+
reply.redirect(301, '/new-route')
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Change it to:
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
// v5
|
|
251
|
+
reply.redirect('/new-route', 301)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This was already deprecated in v4 as `FSTDEP021`, so you should have already
|
|
255
|
+
updated your code to use the new signature.
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
### Modifying `reply.sent` is now forbidden
|
|
259
|
+
|
|
260
|
+
In v4, you could modify the `reply.sent` property to prevent the response from
|
|
261
|
+
being sent.
|
|
262
|
+
This is no longer possible in v5, use `reply.hijack()` instead.
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
// v4
|
|
266
|
+
fastify.get('/route', (req, reply) => {
|
|
267
|
+
reply.sent = true;
|
|
268
|
+
reply.raw.end('hello');
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Change it to:
|
|
273
|
+
|
|
274
|
+
```js
|
|
275
|
+
// v5
|
|
276
|
+
fastify.get('/route', (req, reply) => {
|
|
277
|
+
reply.hijack();
|
|
278
|
+
reply.raw.end('hello');
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
This was already deprecated in v4 as `FSTDEP010`, so you should have already
|
|
283
|
+
updated your code to use the new signature.
|
|
284
|
+
|
|
285
|
+
### Constraints for route versioning signature changes
|
|
286
|
+
|
|
287
|
+
We changed the signature for route versioning constraints.
|
|
288
|
+
The `version` and `versioning` options have been removed and you should
|
|
289
|
+
use the `constraints` option instead.
|
|
290
|
+
|
|
291
|
+
| Code | Description | How to solve | Discussion |
|
|
292
|
+
| ---- | ----------- | ------------ | ---------- |
|
|
293
|
+
| FSTDEP008 | You are using route constraints via the route `{version: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
|
294
|
+
| FSTDEP009 | You are using a custom route versioning strategy via the server `{versioning: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
|
295
|
+
|
|
296
|
+
### `HEAD` routes requires to register before `GET` when `exposeHeadRoutes: true`
|
|
297
|
+
|
|
298
|
+
We have a more strict requirement for custom `HEAD` route when
|
|
299
|
+
`exposeHeadRoutes: true`.
|
|
300
|
+
|
|
301
|
+
When you provides a custom `HEAD` route, you must either explicitly
|
|
302
|
+
set `exposeHeadRoutes` to `false`
|
|
303
|
+
|
|
304
|
+
```js
|
|
305
|
+
// v4
|
|
306
|
+
fastify.get('/route', {
|
|
307
|
+
|
|
308
|
+
}, (req, reply) => {
|
|
309
|
+
reply.send({ hello: 'world' });
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
fastify.head('/route', (req, reply) => {
|
|
313
|
+
// ...
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
```js
|
|
318
|
+
// v5
|
|
319
|
+
fastify.get('/route', {
|
|
320
|
+
exposeHeadRoutes: false
|
|
321
|
+
}, (req, reply) => {
|
|
322
|
+
reply.send({ hello: 'world' });
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
fastify.head('/route', (req, reply) => {
|
|
326
|
+
// ...
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
or place the `HEAD` route before `GET`.
|
|
331
|
+
|
|
332
|
+
```js
|
|
333
|
+
// v5
|
|
334
|
+
fastify.head('/route', (req, reply) => {
|
|
335
|
+
// ...
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
fastify.get('/route', {
|
|
339
|
+
|
|
340
|
+
}, (req, reply) => {
|
|
341
|
+
reply.send({ hello: 'world' });
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
This was changed in [#2700](https://github.com/fastify/fastify/pull/2700),
|
|
346
|
+
and the old behavior was deprecated in v4 as `FSTDEP007`.
|
|
347
|
+
|
|
348
|
+
### Removed `request.connection`
|
|
349
|
+
|
|
350
|
+
The `request.connection` property has been removed in v5.
|
|
351
|
+
You should use `request.socket` instead.
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
// v4
|
|
355
|
+
fastify.get('/route', (req, reply) => {
|
|
356
|
+
console.log(req.connection.remoteAddress);
|
|
357
|
+
return { hello: 'world' };
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
```js
|
|
362
|
+
// v5
|
|
363
|
+
fastify.get('/route', (req, reply) => {
|
|
364
|
+
console.log(req.socket.remoteAddress);
|
|
365
|
+
return { hello: 'world' };
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
This was already deprecated in v4 as `FSTDEP05`, so you should
|
|
370
|
+
have already updated your code to use the new signature.
|
|
371
|
+
|
|
372
|
+
### `reply.getResponseTime()` has been removed, use `reply.elapsedTime` instead
|
|
373
|
+
|
|
374
|
+
The `reply.getResponseTime()` method has been removed in v5.
|
|
375
|
+
You should use `reply.elapsedTime` instead.
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
// v4
|
|
379
|
+
fastify.get('/route', (req, reply) => {
|
|
380
|
+
console.log(reply.getResponseTime());
|
|
381
|
+
return { hello: 'world' };
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
```js
|
|
386
|
+
// v5
|
|
387
|
+
fastify.get('/route', (req, reply) => {
|
|
388
|
+
console.log(reply.elapsedTime);
|
|
389
|
+
return { hello: 'world' };
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This was already deprecated in v4 as `FSTDEP20`, so you should have already
|
|
394
|
+
updated your code to use the new signature.
|
|
395
|
+
|
|
396
|
+
### `fastify.hasRoute()` now matches the behavior of `find-my-way`
|
|
397
|
+
|
|
398
|
+
The `fastify.hasRoute()` method now matches the behavior of `find-my-way`
|
|
399
|
+
and requires the route definition to be passed as it is defined in the route.
|
|
400
|
+
|
|
401
|
+
```js
|
|
402
|
+
// v4
|
|
403
|
+
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
|
|
404
|
+
|
|
405
|
+
console.log(fastify.hasRoute({
|
|
406
|
+
method: 'GET',
|
|
407
|
+
url: '/example/12345.png'
|
|
408
|
+
)); // true
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```js
|
|
412
|
+
// v5
|
|
413
|
+
|
|
414
|
+
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
|
|
415
|
+
|
|
416
|
+
console.log(fastify.hasRoute({
|
|
417
|
+
method: 'GET',
|
|
418
|
+
url: '/example/:file(^\\d+).png'
|
|
419
|
+
)); // true
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Removal of some non-standard HTTP methods
|
|
423
|
+
|
|
424
|
+
We have removed the following HTTP methods from Fastify:
|
|
425
|
+
- `PROPFIND`
|
|
426
|
+
- `PROPPATCH`
|
|
427
|
+
- `MKCOL`
|
|
428
|
+
- `COPY`
|
|
429
|
+
- `MOVE`
|
|
430
|
+
- `LOCK`
|
|
431
|
+
- `UNLOCK`
|
|
432
|
+
- `TRACE`
|
|
433
|
+
- `SEARCH`
|
|
434
|
+
|
|
435
|
+
It's now possible to add them back using the `acceptHTTPMethod` method.
|
|
436
|
+
|
|
437
|
+
```js
|
|
438
|
+
const fastify = Fastify()
|
|
439
|
+
|
|
440
|
+
// add a new http method on top of the default ones:
|
|
441
|
+
fastify.acceptHTTPMethod('REBIND')
|
|
442
|
+
|
|
443
|
+
// add a new HTTP method that accepts a body:
|
|
444
|
+
fastify.acceptHTTPMethod('REBIND', { hasBody: true })
|
|
445
|
+
|
|
446
|
+
// reads the HTTP methods list:
|
|
447
|
+
fastify.supportedMethods // returns a string array
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
See [#5567](https://github.com/fastify/fastify/pull/5567) for more
|
|
451
|
+
information.
|
|
452
|
+
|
|
453
|
+
### Removed support from reference types in decorators
|
|
454
|
+
|
|
455
|
+
Decorating Request/Reply with a reference type (`Array`, `Object`)
|
|
456
|
+
is now prohibited as this reference is shared amongst all requests.
|
|
457
|
+
|
|
458
|
+
```js
|
|
459
|
+
// v4
|
|
460
|
+
fastify.decorateRequest('myObject', { hello: 'world' });
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```js
|
|
464
|
+
// v5
|
|
465
|
+
fastify.decorateRequest('myObject');
|
|
466
|
+
fastify.addHook('onRequest', async (req, reply) => {
|
|
467
|
+
req.myObject = { hello: 'world' };
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
or turn it into a function
|
|
472
|
+
|
|
473
|
+
```js
|
|
474
|
+
// v5
|
|
475
|
+
fastify.decorateRequest('myObject', () => { hello: 'world' });
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
or as a getter
|
|
479
|
+
|
|
480
|
+
```js
|
|
481
|
+
// v5
|
|
482
|
+
fastify.decorateRequest('myObject', {
|
|
483
|
+
getter () {
|
|
484
|
+
return { hello: 'world' }
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
See [#5462](https://github.com/fastify/fastify/pull/5462) for more information.
|
|
490
|
+
|
|
491
|
+
### Remove support for DELETE with a `Content-Type: application/json` header and an empty body
|
|
492
|
+
|
|
493
|
+
In v4, Fastify allowed `DELETE` requests with a `Content-Type: application/json`
|
|
494
|
+
header and an empty body was accepted.
|
|
495
|
+
This is no longer allowed in v5.
|
|
496
|
+
|
|
497
|
+
See [#5419](https://github.com/fastify/fastify/pull/5419) for more information.
|
|
498
|
+
|
|
499
|
+
### Plugins cannot mix callback/promise API anymore
|
|
500
|
+
|
|
501
|
+
In v4, plugins could mix the callback and promise API, leading to unexpected behavior.
|
|
502
|
+
This is no longer allowed in v5.
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
// v4
|
|
506
|
+
fastify.register(async function (instance, opts, done) {
|
|
507
|
+
done();
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
```js
|
|
512
|
+
// v5
|
|
513
|
+
fastify.register(async function (instance, opts) {
|
|
514
|
+
return;
|
|
515
|
+
});
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
or
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
// v5
|
|
522
|
+
fastify.register(function (instance, opts, done) {
|
|
523
|
+
done();
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Removes `getDefaultRoute` and `setDefaultRoute` methods
|
|
528
|
+
|
|
529
|
+
The `getDefaultRoute` and `setDefaultRoute` methods have been removed in v5.
|
|
530
|
+
|
|
531
|
+
See [#4485](https://github.com/fastify/fastify/pull/4485)
|
|
532
|
+
and [#4480](https://github.com/fastify/fastify/pull/4485)
|
|
533
|
+
for more information.
|
|
534
|
+
This was already deprecated in v4 as `FSTDEP014`,
|
|
535
|
+
so you should have already updated your code.
|
|
536
|
+
|
|
537
|
+
## New Features
|
|
538
|
+
|
|
539
|
+
### Diagnostic Channel support
|
|
540
|
+
|
|
541
|
+
Fastify v5 now supports the [Diagnostic Channel](https://nodejs.org/api/diagnostic_channel.html)
|
|
542
|
+
API natively
|
|
543
|
+
and provides a way to trace the lifecycle of a request.
|
|
544
|
+
|
|
545
|
+
```js
|
|
546
|
+
'use strict'
|
|
547
|
+
|
|
548
|
+
const diagnostics = require('node:diagnostics_channel')
|
|
549
|
+
const sget = require('simple-get').concat
|
|
550
|
+
const Fastify = require('fastify')
|
|
551
|
+
|
|
552
|
+
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
|
|
553
|
+
console.log(msg.route.url) // '/:id'
|
|
554
|
+
console.log(msg.route.method) // 'GET'
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
|
|
558
|
+
// msg is the same as the one emitted by the 'tracing:fastify.request.handler:start' channel
|
|
559
|
+
console.log(msg)
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
|
|
563
|
+
// in case of error
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
const fastify = Fastify()
|
|
567
|
+
fastify.route({
|
|
568
|
+
method: 'GET',
|
|
569
|
+
url: '/:id',
|
|
570
|
+
handler: function (req, reply) {
|
|
571
|
+
return { hello: 'world' }
|
|
572
|
+
}
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
fastify.listen({ port: 0 }, function () {
|
|
576
|
+
sget({
|
|
577
|
+
method: 'GET',
|
|
578
|
+
url: fastify.listeningOrigin + '/7'
|
|
579
|
+
}, (err, response, body) => {
|
|
580
|
+
t.error(err)
|
|
581
|
+
t.equal(response.statusCode, 200)
|
|
582
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
583
|
+
})
|
|
584
|
+
})
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
See the [documentation](https://github.com/fastify/fastify/blob/main/docs/Reference/Hooks.md#diagnostics-channel-hooks)
|
|
588
|
+
and [#5252](https://github.com/fastify/fastify/pull/5252) for additional details.
|
package/docs/Reference/LTS.md
CHANGED
|
@@ -57,7 +57,8 @@ A "month" is defined as 30 consecutive days.
|
|
|
57
57
|
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
|
|
58
58
|
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
|
|
59
59
|
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
|
|
60
|
-
| 4.0.0 | 2022-06-08 |
|
|
60
|
+
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
|
|
61
|
+
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
|
|
61
62
|
|
|
62
63
|
### CI tested operating systems
|
|
63
64
|
|
|
@@ -71,10 +72,10 @@ YAML workflow labels below:
|
|
|
71
72
|
|
|
72
73
|
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
|
|
73
74
|
| ------- | ------------------- | --------------- | ----------- | ------------- |
|
|
74
|
-
| Linux | `ubuntu-latest`
|
|
75
|
-
| Linux | `ubuntu-latest`
|
|
76
|
-
| Windows | `windows-latest`
|
|
77
|
-
| MacOS | `macos-latest`
|
|
75
|
+
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
|
|
76
|
+
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
|
|
77
|
+
| Windows | `windows-latest` | npm | 20 | v5(20) |
|
|
78
|
+
| MacOS | `macos-latest` | npm | 20 | v5(20) |
|
|
78
79
|
|
|
79
80
|
Using [yarn](https://yarnpkg.com/) might require passing the `--ignore-engines`
|
|
80
81
|
flag.
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '5.0.0
|
|
3
|
+
const VERSION = '5.0.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -673,7 +673,7 @@ function fastify (options) {
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
if (name === 'onClose') {
|
|
676
|
-
this.onClose(fn)
|
|
676
|
+
this.onClose(fn.bind(this))
|
|
677
677
|
} else if (name === 'onReady' || name === 'onListen' || name === 'onRoute') {
|
|
678
678
|
this[kHooks].add(name, fn)
|
|
679
679
|
} else {
|
package/lib/warnings.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "5.0.0
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
"dependencies": {
|
|
193
193
|
"@fastify/ajv-compiler": "^4.0.0",
|
|
194
194
|
"@fastify/error": "^4.0.0",
|
|
195
|
-
"@fastify/fast-json-stringify-compiler": "^
|
|
195
|
+
"@fastify/fast-json-stringify-compiler": "^5.0.0",
|
|
196
196
|
"abstract-logging": "^2.0.1",
|
|
197
197
|
"avvio": "^9.0.0",
|
|
198
198
|
"fast-json-stringify": "^6.0.0",
|
package/test/close.test.js
CHANGED
|
@@ -9,11 +9,14 @@ const split = require('split2')
|
|
|
9
9
|
const { sleep } = require('./helper')
|
|
10
10
|
|
|
11
11
|
test('close callback', t => {
|
|
12
|
-
t.plan(
|
|
12
|
+
t.plan(7)
|
|
13
13
|
const fastify = Fastify()
|
|
14
14
|
fastify.addHook('onClose', onClose)
|
|
15
15
|
function onClose (instance, done) {
|
|
16
|
+
t.type(fastify, this)
|
|
16
17
|
t.type(fastify, instance)
|
|
18
|
+
t.equal(fastify, this)
|
|
19
|
+
t.equal(fastify, instance)
|
|
17
20
|
done()
|
|
18
21
|
}
|
|
19
22
|
|
package/test/hooks.test.js
CHANGED
|
@@ -3072,13 +3072,14 @@ test('preSerialization hooks should support encapsulation', t => {
|
|
|
3072
3072
|
})
|
|
3073
3073
|
|
|
3074
3074
|
test('onRegister hook should be called / 1', t => {
|
|
3075
|
-
t.plan(
|
|
3075
|
+
t.plan(4)
|
|
3076
3076
|
const fastify = Fastify()
|
|
3077
3077
|
|
|
3078
|
-
fastify.addHook('onRegister', (instance, opts) => {
|
|
3078
|
+
fastify.addHook('onRegister', (instance, opts, done) => {
|
|
3079
3079
|
// duck typing for the win!
|
|
3080
3080
|
t.ok(instance.addHook)
|
|
3081
3081
|
t.same(opts, pluginOpts)
|
|
3082
|
+
t.notOk(done)
|
|
3082
3083
|
})
|
|
3083
3084
|
|
|
3084
3085
|
const pluginOpts = { prefix: 'hello', custom: 'world' }
|
|
@@ -131,12 +131,9 @@ server.addHook('onRoute', function (opts) {
|
|
|
131
131
|
expectType<RouteOptions & { routePath: string; path: string; prefix: string }>(opts)
|
|
132
132
|
})
|
|
133
133
|
|
|
134
|
-
server.addHook('onRegister', (instance, opts
|
|
134
|
+
server.addHook('onRegister', (instance, opts) => {
|
|
135
135
|
expectType<FastifyInstance>(instance)
|
|
136
136
|
expectType<RegisterOptions & FastifyPluginOptions>(opts)
|
|
137
|
-
expectAssignable<(err?: FastifyError) => void>(done)
|
|
138
|
-
expectAssignable<(err?: NodeJS.ErrnoException) => void>(done)
|
|
139
|
-
expectType<void>(done(new Error()))
|
|
140
137
|
})
|
|
141
138
|
|
|
142
139
|
server.addHook('onReady', function (done) {
|
|
@@ -152,7 +149,8 @@ server.addHook('onListen', function (done) {
|
|
|
152
149
|
expectAssignable<(err?: NodeJS.ErrnoException) => void>(done)
|
|
153
150
|
})
|
|
154
151
|
|
|
155
|
-
server.addHook('onClose', (instance, done)
|
|
152
|
+
server.addHook('onClose', function (instance, done) {
|
|
153
|
+
expectType<FastifyInstance>(this)
|
|
156
154
|
expectType<FastifyInstance>(instance)
|
|
157
155
|
expectAssignable<(err?: FastifyError) => void>(done)
|
|
158
156
|
expectAssignable<(err?: NodeJS.ErrnoException) => void>(done)
|
|
@@ -237,7 +235,8 @@ server.addHook('onListen', async function () {
|
|
|
237
235
|
expectType<FastifyInstance>(this)
|
|
238
236
|
})
|
|
239
237
|
|
|
240
|
-
server.addHook('onClose', async (instance)
|
|
238
|
+
server.addHook('onClose', async function (instance) {
|
|
239
|
+
expectType<FastifyInstance>(this)
|
|
241
240
|
expectType<FastifyInstance>(instance)
|
|
242
241
|
})
|
|
243
242
|
|
|
@@ -370,11 +370,12 @@ expectError(server.decorate<string>('test', true))
|
|
|
370
370
|
expectError(server.decorate<(myNumber: number) => number>('test', function (myNumber: number): string {
|
|
371
371
|
return ''
|
|
372
372
|
}))
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
373
|
+
// TODO(mcollina): uncomment after https://github.com/tsdjs/tsd/pull/220 lands.
|
|
374
|
+
// expectError(server.decorate<string>('test', {
|
|
375
|
+
// getter () {
|
|
376
|
+
// return true
|
|
377
|
+
// }
|
|
378
|
+
// }))
|
|
378
379
|
expectError(server.decorate<string>('test', {
|
|
379
380
|
setter (x) {}
|
|
380
381
|
}))
|
|
@@ -418,11 +419,12 @@ server.decorate('typedTestProperty')
|
|
|
418
419
|
server.decorate('typedTestProperty', null, ['foo'])
|
|
419
420
|
expectError(server.decorate('typedTestProperty', null))
|
|
420
421
|
expectError(server.decorate('typedTestProperty', 'foo'))
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
422
|
+
// TODO(mcollina): uncomment after https://github.com/tsdjs/tsd/pull/220 lands.
|
|
423
|
+
// expectError(server.decorate('typedTestProperty', {
|
|
424
|
+
// getter () {
|
|
425
|
+
// return 'foo'
|
|
426
|
+
// }
|
|
427
|
+
// }))
|
|
426
428
|
server.decorate('typedTestMethod', function (x) {
|
|
427
429
|
expectType<string>(x)
|
|
428
430
|
expectType<FastifyInstance>(this)
|
package/types/hooks.d.ts
CHANGED
|
@@ -711,9 +711,8 @@ export interface onRegisterHookHandler<
|
|
|
711
711
|
> {
|
|
712
712
|
(
|
|
713
713
|
instance: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
|
|
714
|
-
opts: RegisterOptions & Options
|
|
715
|
-
|
|
716
|
-
): Promise<unknown> | void; // documentation is missing the `done` method
|
|
714
|
+
opts: RegisterOptions & Options
|
|
715
|
+
): Promise<unknown> | void;
|
|
717
716
|
}
|
|
718
717
|
|
|
719
718
|
/**
|
|
@@ -782,6 +781,7 @@ export interface onCloseHookHandler<
|
|
|
782
781
|
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
|
783
782
|
> {
|
|
784
783
|
(
|
|
784
|
+
this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
|
|
785
785
|
instance: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
|
|
786
786
|
done: HookHandlerDoneFunction
|
|
787
787
|
): void;
|
|
@@ -795,6 +795,7 @@ export interface onCloseAsyncHookHandler<
|
|
|
795
795
|
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
|
796
796
|
> {
|
|
797
797
|
(
|
|
798
|
+
this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
|
|
798
799
|
instance: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>
|
|
799
800
|
): Promise<unknown>;
|
|
800
801
|
}
|