fastify 4.15.0 → 4.16.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 +3 -3
- package/docs/Guides/Database.md +7 -8
- package/docs/Guides/Ecosystem.md +16 -7
- package/docs/Guides/Getting-Started.md +1 -1
- package/docs/Guides/Migration-Guide-V4.md +21 -0
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Prototype-Poisoning.md +31 -39
- package/docs/Guides/Recommendations.md +1 -1
- package/docs/Guides/Write-Type-Provider.md +3 -3
- package/docs/Reference/Hooks.md +42 -9
- package/docs/Reference/Reply.md +2 -2
- package/docs/Reference/Routes.md +13 -2
- package/docs/Reference/Server.md +19 -3
- package/docs/Reference/Type-Providers.md +1 -1
- package/docs/Reference/TypeScript.md +3 -3
- package/docs/index.md +2 -2
- package/examples/benchmark/parser.js +47 -0
- package/fastify.js +26 -23
- package/lib/error-serializer.js +9 -162
- package/lib/hooks.js +3 -0
- package/lib/server.js +9 -4
- package/lib/validation.js +10 -8
- package/lib/warnings.js +2 -0
- package/package.json +7 -6
- package/test/close.test.js +91 -0
- package/test/route-hooks.test.js +29 -0
- package/test/route.test.js +1 -1
- package/test/schema-feature.test.js +128 -35
- package/test/serial/logger.0.test.js +861 -0
- package/test/serial/logger.1.test.js +862 -0
- package/test/serial/tap-parallel-not-ok +0 -0
- package/test/server.test.js +10 -0
- package/test/types/hooks.test-d.ts +66 -11
- package/test/types/import.js +1 -1
- package/test/types/instance.test-d.ts +2 -0
- package/test/types/route.test-d.ts +106 -5
- package/test/types/type-provider.test-d.ts +77 -10
- package/types/hooks.d.ts +28 -0
- package/types/instance.d.ts +20 -1
- package/types/logger.d.ts +1 -1
- package/types/route.d.ts +41 -11
- package/test/logger.test.js +0 -1721
package/README.md
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
<div align="center">
|
|
11
11
|
|
|
12
|
-
[](https://github.com/fastify/fastify/actions/workflows/ci.yml)
|
|
12
|
+
[](https://github.com/fastify/fastify/actions/workflows/ci.yml)
|
|
13
13
|
[](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
|
14
|
+
CI](https://github.com/fastify/fastify/workflows/package-manager-ci/badge.svg?branch=main)](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
|
15
15
|
[](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
|
16
|
+
SIte](https://github.com/fastify/fastify/workflows/website/badge.svg?branch=main)](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
|
17
17
|
[](https://standardjs.com/)
|
|
18
18
|
|
|
19
19
|
</div>
|
package/docs/Guides/Database.md
CHANGED
|
@@ -130,19 +130,18 @@ fastify.register(require('@fastify/mongodb'), {
|
|
|
130
130
|
url: 'mongodb://mongo/mydb'
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
-
fastify.get('/user/:id', function (req, reply) {
|
|
133
|
+
fastify.get('/user/:id', async function (req, reply) {
|
|
134
134
|
// Or this.mongo.client.db('mydb').collection('users')
|
|
135
135
|
const users = this.mongo.db.collection('users')
|
|
136
136
|
|
|
137
137
|
// if the id is an ObjectId format, you need to create a new ObjectId
|
|
138
138
|
const id = this.mongo.ObjectId(req.params.id)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
})
|
|
139
|
+
try {
|
|
140
|
+
const user = await users.findOne({ id })
|
|
141
|
+
return user
|
|
142
|
+
} catch (err) {
|
|
143
|
+
return err
|
|
144
|
+
}
|
|
146
145
|
})
|
|
147
146
|
|
|
148
147
|
fastify.listen({ port: 3000 }, err => {
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -11,7 +11,7 @@ section.
|
|
|
11
11
|
- [`@fastify/accepts`](https://github.com/fastify/fastify-accepts) to have
|
|
12
12
|
[accepts](https://www.npmjs.com/package/accepts) in your request object.
|
|
13
13
|
- [`@fastify/accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer)
|
|
14
|
-
to serialize to output according to `Accept` header.
|
|
14
|
+
to serialize to output according to the `Accept` header.
|
|
15
15
|
- [`@fastify/any-schema`](https://github.com/fastify/any-schema-you-like) Save
|
|
16
16
|
multiple schemas and decide which one to use to serialize the payload
|
|
17
17
|
- [`@fastify/auth`](https://github.com/fastify/fastify-auth) Run multiple auth
|
|
@@ -151,7 +151,7 @@ section.
|
|
|
151
151
|
- [`@eropple/fastify-openapi3`](https://github.com/eropple/fastify-openapi3) Provides
|
|
152
152
|
easy, developer-friendly OpenAPI 3.1 specs + doc explorer based on your routes.
|
|
153
153
|
- [`@ethicdevs/fastify-custom-session`](https://github.com/EthicDevs/fastify-custom-session)
|
|
154
|
-
A plugin
|
|
154
|
+
A plugin lets you use session and decide only where to load/save from/to. Has
|
|
155
155
|
great TypeScript support + built-in adapters for common ORMs/databases (Firebase,
|
|
156
156
|
Prisma Client, Postgres (wip), InMemory) and you can easily make your own adapter!
|
|
157
157
|
- [`@ethicdevs/fastify-git-server`](https://github.com/EthicDevs/fastify-git-server)
|
|
@@ -174,7 +174,6 @@ section.
|
|
|
174
174
|
- [`@immobiliarelabs/fastify-sentry`](https://github.com/immobiliare/fastify-sentry)
|
|
175
175
|
Sentry errors handler that just works! Install, add your DSN and you're good
|
|
176
176
|
to go!
|
|
177
|
-
- [`@mateonunez/fastify-lyra`](https://github.com/mateonunez/fastify-lyra)
|
|
178
177
|
A plugin to implement [Lyra](https://github.com/nearform/lyra) search engine
|
|
179
178
|
on Fastify
|
|
180
179
|
- [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit)
|
|
@@ -391,9 +390,11 @@ section.
|
|
|
391
390
|
- [`fastify-keycloak-adapter`](https://github.com/yubinTW/fastify-keycloak-adapter)
|
|
392
391
|
A keycloak adapter for a Fastify app.
|
|
393
392
|
- [`fastify-knexjs`](https://github.com/chapuletta/fastify-knexjs) Fastify
|
|
394
|
-
plugin for
|
|
393
|
+
plugin for supporting KnexJS Query Builder.
|
|
395
394
|
- [`fastify-knexjs-mock`](https://github.com/chapuletta/fastify-knexjs-mock)
|
|
396
395
|
Fastify Mock KnexJS for testing support.
|
|
396
|
+
- [`fastify-koa`](https://github.com/rozzilla/fastify-koa) Convert Koa
|
|
397
|
+
middlewares into Fastify plugins
|
|
397
398
|
- [`fastify-kubernetes`](https://github.com/greguz/fastify-kubernetes) Fastify
|
|
398
399
|
Kubernetes client plugin.
|
|
399
400
|
- [`fastify-language-parser`](https://github.com/lependu/fastify-language-parser)
|
|
@@ -401,13 +402,14 @@ section.
|
|
|
401
402
|
- [`fastify-lcache`](https://github.com/denbon05/fastify-lcache)
|
|
402
403
|
Lightweight cache plugin
|
|
403
404
|
- [`fastify-list-routes`](https://github.com/chuongtrh/fastify-list-routes)
|
|
404
|
-
A simple plugin for Fastify list all available routes.
|
|
405
|
+
A simple plugin for Fastify to list all available routes.
|
|
405
406
|
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from
|
|
406
407
|
a directory and inject the Fastify instance in each file.
|
|
408
|
+
- [`fastify-log-controller`](https://github.com/Eomm/fastify-log-controller/)
|
|
409
|
+
changes the log level of your Fastify server at runtime.
|
|
407
410
|
- [`fastify-lured`](https://github.com/lependu/fastify-lured) Plugin to load lua
|
|
408
411
|
scripts with [fastify-redis](https://github.com/fastify/fastify-redis) and
|
|
409
412
|
[lured](https://github.com/enobufs/lured).
|
|
410
|
-
- [`fastify-lyra`](https://github.com/mateonunez/fastify-lyra)
|
|
411
413
|
A plugin to implement [Lyra](https://github.com/LyraSearch/lyra) search engine
|
|
412
414
|
on Fastify.
|
|
413
415
|
- [`fastify-mailer`](https://github.com/coopflow/fastify-mailer) Plugin to
|
|
@@ -475,6 +477,7 @@ section.
|
|
|
475
477
|
- [`fastify-oracle`](https://github.com/cemremengu/fastify-oracle) Attaches an
|
|
476
478
|
[`oracledb`](https://github.com/oracle/node-oracledb) connection pool to a
|
|
477
479
|
Fastify server instance.
|
|
480
|
+
- [`fastify-orama`](https://github.com/mateonunez/fastify-orama)
|
|
478
481
|
- [`fastify-orientdb`](https://github.com/mahmed8003/fastify-orientdb) Fastify
|
|
479
482
|
OrientDB connection plugin, with which you can share the OrientDB connection
|
|
480
483
|
across every part of your server.
|
|
@@ -518,6 +521,8 @@ section.
|
|
|
518
521
|
- [`fastify-redis-channels`](https://github.com/hearit-io/fastify-redis-channels)
|
|
519
522
|
A plugin for fast, reliable, and scalable channels implementation based on
|
|
520
523
|
Redis streams.
|
|
524
|
+
- [`fastify-redis-session`](https://github.com/mohammadraufzahed/fastify-redis-session)
|
|
525
|
+
Redis Session plugin for fastify.
|
|
521
526
|
- [`fastify-register-routes`](https://github.com/israeleriston/fastify-register-routes)
|
|
522
527
|
Plugin to automatically load routes from a specified path and optionally limit
|
|
523
528
|
loaded file names by a regular expression.
|
|
@@ -586,6 +591,10 @@ section.
|
|
|
586
591
|
TOTP (e.g. for 2FA).
|
|
587
592
|
- [`fastify-twitch-ebs-tools`](https://github.com/lukemnet/fastify-twitch-ebs-tools)
|
|
588
593
|
Useful functions for Twitch Extension Backend Services (EBS).
|
|
594
|
+
- [`fastify-type-provider-effect-schema`](https://github.com/daotl/fastify-type-provider-effect-schema)
|
|
595
|
+
Fastify
|
|
596
|
+
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/)
|
|
597
|
+
for [@effect/schema](https://github.com/effect-ts/schema).
|
|
589
598
|
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
|
|
590
599
|
Fastify
|
|
591
600
|
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/)
|
|
@@ -637,7 +646,7 @@ section.
|
|
|
637
646
|
- [`openapi-validator-middleware`](https://github.com/PayU/openapi-validator-middleware#fastify)
|
|
638
647
|
Swagger and OpenAPI 3.0 spec-based request validation middleware that supports
|
|
639
648
|
Fastify.
|
|
640
|
-
- [`pubsub-http-handler`](https://github.com/
|
|
649
|
+
- [`pubsub-http-handler`](https://github.com/simenandre/pubsub-http-handler) A Fastify
|
|
641
650
|
plugin to easily create Google Cloud PubSub endpoints.
|
|
642
651
|
- [`sequelize-fastify`](https://github.com/hsynlms/sequelize-fastify) A simple
|
|
643
652
|
and lightweight Sequelize plugin for Fastify.
|
|
@@ -538,7 +538,7 @@ an amazing [ecosystem](./Ecosystem.md)!
|
|
|
538
538
|
<a id="test-server"></a>
|
|
539
539
|
|
|
540
540
|
Fastify does not offer a testing framework, but we do recommend a way to write
|
|
541
|
-
your tests that
|
|
541
|
+
your tests that use the features and architecture of Fastify.
|
|
542
542
|
|
|
543
543
|
Read the [testing](./Testing.md) documentation to learn more!
|
|
544
544
|
|
|
@@ -130,6 +130,27 @@ As a result, if you specify an `onRoute` hook in a plugin you should now either:
|
|
|
130
130
|
});
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
### Optional URL parameters
|
|
134
|
+
|
|
135
|
+
If you've already used any implicitly optional parameters, you'll get a 404
|
|
136
|
+
error when trying to access the route. You will now need to declare the
|
|
137
|
+
optional parameters explicitly.
|
|
138
|
+
|
|
139
|
+
For example, if you have the same route for listing and showing a post,
|
|
140
|
+
refactor this:
|
|
141
|
+
```js
|
|
142
|
+
fastify.get('/posts/:id', (request, reply) => {
|
|
143
|
+
const { id } = request.params;
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Into this:
|
|
148
|
+
```js
|
|
149
|
+
fastify.get('/posts/:id?', (request, reply) => {
|
|
150
|
+
const { id } = request.params;
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
133
154
|
## Non-Breaking Changes
|
|
134
155
|
|
|
135
156
|
### Deprecation of variadic `.listen()` signature
|
|
@@ -427,7 +427,7 @@ variables that were injected by preceding plugins in the order of declaration.
|
|
|
427
427
|
|
|
428
428
|
ESM is supported as well from [Node.js
|
|
429
429
|
`v13.3.0`](https://nodejs.org/api/esm.html) and above! Just export your plugin
|
|
430
|
-
as ESM module and you are good to go!
|
|
430
|
+
as an ESM module and you are good to go!
|
|
431
431
|
|
|
432
432
|
```js
|
|
433
433
|
// plugin.mjs
|
|
@@ -4,29 +4,24 @@
|
|
|
4
4
|
> but otherwise remains the same. The original HTML can be retrieved from the
|
|
5
5
|
> above permission link.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## History behind prototype poisoning
|
|
8
8
|
<a id="pp"></a>
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
verify your own code first. While this story is focused on a specific framework,
|
|
22
|
-
any solution that uses `JSON.parse()` to process external data is potentially at
|
|
23
|
-
risk.
|
|
10
|
+
Based on the article by Eran Hammer,the issue is created by a web security bug.
|
|
11
|
+
It is also a perfect illustration of the efforts required to maintain
|
|
12
|
+
open-source software and the limitations of existing communication channels.
|
|
13
|
+
|
|
14
|
+
But first, if we use a JavaScript framework to process incoming JSON data, take
|
|
15
|
+
a moment to read up on [Prototype Poisoning](https://medium.com/intrinsic/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96)
|
|
16
|
+
in general, and the specific [technical details]
|
|
17
|
+
(https://github.com/hapijs/hapi/issues/3916) of this issue.
|
|
18
|
+
This could be a critical issue so, we might need to verify your own code first.
|
|
19
|
+
It focuses on specific framework however, any solution that uses `JSON.parse()`
|
|
20
|
+
to process external data is potentially at risk.
|
|
24
21
|
|
|
25
22
|
### BOOM
|
|
26
23
|
<a id="pp-boom"></a>
|
|
27
24
|
|
|
28
|
-
Our story begins with a bang.
|
|
29
|
-
|
|
30
25
|
The engineering team at Lob (long time generous supporters of my work!) reported
|
|
31
26
|
a critical security vulnerability they identified in our data validation
|
|
32
27
|
module — [joi](https://github.com/hapijs/joi). They provided some technical
|
|
@@ -34,21 +29,22 @@ details and a proposed solution.
|
|
|
34
29
|
|
|
35
30
|
The main purpose of a data validation library is to ensure the output fully
|
|
36
31
|
complies with the rules defined. If it doesn't, validation fails. If it passes,
|
|
37
|
-
|
|
32
|
+
we can blindly trust that the data you are working with is safe. In fact, most
|
|
38
33
|
developers treat validated input as completely safe from a system integrity
|
|
39
|
-
perspective
|
|
34
|
+
perspective which is crucial!
|
|
40
35
|
|
|
41
|
-
In our case, the Lob team provided an example where some data was able to
|
|
36
|
+
In our case, the Lob team provided an example where some data was able to escape
|
|
42
37
|
by the validation logic and pass through undetected. This is the worst possible
|
|
43
38
|
defect a validation library can have.
|
|
44
39
|
|
|
45
40
|
### Prototype in a nutshell
|
|
46
41
|
<a id="pp-nutshell"></a>
|
|
47
42
|
|
|
48
|
-
To understand this
|
|
43
|
+
To understand this, we need to understand how JavaScript works a bit.
|
|
49
44
|
Every object in JavaScript can have a prototype. It is a set of methods and
|
|
50
|
-
properties it "inherits" from another object. I put inherits in quotes
|
|
51
|
-
JavaScript isn't really an object
|
|
45
|
+
properties it "inherits" from another object. I have put inherits in quotes
|
|
46
|
+
because JavaScript isn't really an object-oriented language.It is prototype-
|
|
47
|
+
based object-oriented language.
|
|
52
48
|
|
|
53
49
|
A long time ago, for a bunch of irrelevant reasons, someone decided that it
|
|
54
50
|
would be a good idea to use the special property name `__proto__` to access (and
|
|
@@ -68,22 +64,21 @@ To demonstrate:
|
|
|
68
64
|
{ b: 5 }
|
|
69
65
|
```
|
|
70
66
|
|
|
71
|
-
|
|
67
|
+
The object doesn't have a `c` property, but its prototype does.
|
|
72
68
|
When validating the object, the validation library ignores the prototype and
|
|
73
69
|
only validates the object's own properties. This allows `c` to sneak in via the
|
|
74
70
|
prototype.
|
|
75
71
|
|
|
76
|
-
Another important part
|
|
77
|
-
provided by the language to convert JSON formatted text into
|
|
78
|
-
this magic `__proto__` property name.
|
|
72
|
+
Another important part is the way `JSON.parse()` — a utility
|
|
73
|
+
provided by the language to convert JSON formatted text into
|
|
74
|
+
objects — handles this magic `__proto__` property name.
|
|
79
75
|
|
|
80
76
|
```
|
|
81
|
-
> const text = '{
|
|
77
|
+
> const text = '{"b": 5, "__proto__": { "c": 6 }}';
|
|
82
78
|
> const a = JSON.parse(text);
|
|
83
79
|
> a;
|
|
84
|
-
{
|
|
80
|
+
{b: 5, __proto__: { c: 6 }}
|
|
85
81
|
```
|
|
86
|
-
|
|
87
82
|
Notice how `a` has a `__proto__` property. This is not a prototype reference. It
|
|
88
83
|
is a simple object property key, just like `b`. As we've seen from the first
|
|
89
84
|
example, we can't actually create this key through assignment as that invokes
|
|
@@ -111,17 +106,17 @@ level properties of `a` into the provided empty `{}` object), the magic
|
|
|
111
106
|
|
|
112
107
|
Surprise!
|
|
113
108
|
|
|
114
|
-
|
|
115
|
-
then perform some simple manipulation of that object (
|
|
116
|
-
an `id` ), and
|
|
117
|
-
via `__proto__
|
|
109
|
+
If you get some external text input and parse it with `JSON.parse()`
|
|
110
|
+
then perform some simple manipulation of that object (e.g shallow clone and add
|
|
111
|
+
an `id` ), and pass it to our validation library, it would sneak in undetected
|
|
112
|
+
via `__proto__`.
|
|
118
113
|
|
|
119
114
|
### Oh joi!
|
|
120
115
|
<a id="pp-oh-joi"></a>
|
|
121
116
|
|
|
122
117
|
The first question is, of course, why does the validation module **joi** ignore
|
|
123
118
|
the prototype and let potentially harmful data through? We asked ourselves the
|
|
124
|
-
same question and our instant thought was "it was an oversight". A bug
|
|
119
|
+
same question and our instant thought was "it was an oversight". A bug - a really
|
|
125
120
|
big mistake. The joi module should not have allowed this to happen. But…
|
|
126
121
|
|
|
127
122
|
While joi is used primarily for validating web input data, it also has a
|
|
@@ -166,7 +161,6 @@ will share with the world how to exploit this vulnerability while also making it
|
|
|
166
161
|
more time consuming for systems to upgrade (breaking changes never get applied
|
|
167
162
|
automatically by build tools).
|
|
168
163
|
|
|
169
|
-
Lose — Lose.
|
|
170
164
|
|
|
171
165
|
### A detour
|
|
172
166
|
<a id="pp-detour"></a>
|
|
@@ -386,6 +380,4 @@ plan](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-
|
|
|
386
380
|
coming in March. You can read more about it
|
|
387
381
|
[here](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-licensing-a-preview-f982662ee898).
|
|
388
382
|
|
|
389
|
-
|
|
390
|
-
successfully conveyed not just the technical details, but also the human drama and
|
|
391
|
-
what it takes to keep the web secure.
|
|
383
|
+
|
|
@@ -326,7 +326,7 @@ frequently. Also, the main thread won't have to stop to let the GC run.
|
|
|
326
326
|
|
|
327
327
|
* To optimize for throughput (handling the largest possible amount of
|
|
328
328
|
requests per second per vCPU available), consider using a smaller amount of vCPUs
|
|
329
|
-
per app instance. It is totally fine to run Node.js
|
|
329
|
+
per app instance. It is totally fine to run Node.js applications with 1 vCPU.
|
|
330
330
|
|
|
331
331
|
* You may experiment with an even smaller amount of vCPU, which may provide
|
|
332
332
|
even better throughput in certain use-cases. There are reports of API gateway
|
|
@@ -13,11 +13,11 @@ up to `unknown`.
|
|
|
13
13
|
The reasoning is that certain methods of `FastifyInstance` are
|
|
14
14
|
contravariant on `TypeProvider`, which can lead to TypeScript surfacing
|
|
15
15
|
assignability issues unless the custom type provider interface is
|
|
16
|
-
|
|
16
|
+
substitutable with `FastifyTypeProviderDefault`.
|
|
17
17
|
|
|
18
18
|
For example, `FastifyTypeProviderDefault` will not be assignable to the following:
|
|
19
19
|
```ts
|
|
20
|
-
export interface
|
|
20
|
+
export interface NotSubstitutableTypeProvider extends FastifyTypeProvider {
|
|
21
21
|
// bad, nothing is assignable to `never` (except for itself)
|
|
22
22
|
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
|
|
23
23
|
}
|
|
@@ -25,7 +25,7 @@ export interface NotSubstitutibleTypeProvider extends FastifyTypeProvider {
|
|
|
25
25
|
|
|
26
26
|
Unless changed to:
|
|
27
27
|
```ts
|
|
28
|
-
export interface
|
|
28
|
+
export interface SubstitutableTypeProvider extends FastifyTypeProvider {
|
|
29
29
|
// good, anything can be assigned to `unknown`
|
|
30
30
|
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
|
|
31
31
|
}
|
package/docs/Reference/Hooks.md
CHANGED
|
@@ -25,6 +25,7 @@ are Request/Reply hooks and application hooks:
|
|
|
25
25
|
- [Application Hooks](#application-hooks)
|
|
26
26
|
- [onReady](#onready)
|
|
27
27
|
- [onClose](#onclose)
|
|
28
|
+
- [preClose](#preclose)
|
|
28
29
|
- [onRoute](#onroute)
|
|
29
30
|
- [onRegister](#onregister)
|
|
30
31
|
- [Scope](#scope)
|
|
@@ -266,19 +267,19 @@ fastify.addHook('onTimeout', async (request, reply) => {
|
|
|
266
267
|
`onTimeout` is useful if you need to monitor the request timed out in your
|
|
267
268
|
service (if the `connectionTimeout` property is set on the Fastify instance).
|
|
268
269
|
The `onTimeout` hook is executed when a request is timed out and the HTTP socket
|
|
269
|
-
has been
|
|
270
|
+
has been hung up. Therefore, you will not be able to send data to the client.
|
|
270
271
|
|
|
271
272
|
### onRequestAbort
|
|
272
273
|
|
|
273
274
|
```js
|
|
274
|
-
fastify.addHook('onRequestAbort', (request,
|
|
275
|
+
fastify.addHook('onRequestAbort', (request, done) => {
|
|
275
276
|
// Some code
|
|
276
277
|
done()
|
|
277
278
|
})
|
|
278
279
|
```
|
|
279
280
|
Or `async/await`:
|
|
280
281
|
```js
|
|
281
|
-
fastify.addHook('onRequestAbort', async (request
|
|
282
|
+
fastify.addHook('onRequestAbort', async (request) => {
|
|
282
283
|
// Some code
|
|
283
284
|
await asyncMethod()
|
|
284
285
|
})
|
|
@@ -385,6 +386,7 @@ You can hook into the application-lifecycle as well.
|
|
|
385
386
|
|
|
386
387
|
- [onReady](#onready)
|
|
387
388
|
- [onClose](#onclose)
|
|
389
|
+
- [preClose](#preclose)
|
|
388
390
|
- [onRoute](#onroute)
|
|
389
391
|
- [onRegister](#onregister)
|
|
390
392
|
|
|
@@ -414,9 +416,10 @@ fastify.addHook('onReady', async function () {
|
|
|
414
416
|
### onClose
|
|
415
417
|
<a id="on-close"></a>
|
|
416
418
|
|
|
417
|
-
Triggered when `fastify.close()` is invoked to stop the server
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
Triggered when `fastify.close()` is invoked to stop the server, after all in-flight
|
|
420
|
+
HTTP requests have been completed.
|
|
421
|
+
It is useful when [plugins](./Plugins.md) need a "shutdown" event, for example,
|
|
422
|
+
to close an open connection to a database.
|
|
420
423
|
|
|
421
424
|
The hook function takes the Fastify instance as a first argument,
|
|
422
425
|
and a `done` callback for synchronous hook functions.
|
|
@@ -434,10 +437,34 @@ fastify.addHook('onClose', async (instance) => {
|
|
|
434
437
|
})
|
|
435
438
|
```
|
|
436
439
|
|
|
440
|
+
### preClose
|
|
441
|
+
<a id="pre-close"></a>
|
|
442
|
+
|
|
443
|
+
Triggered when `fastify.close()` is invoked to stop the server, before all in-flight
|
|
444
|
+
HTTP requests have been completed.
|
|
445
|
+
It is useful when [plugins](./Plugins.md) have set up some state attached
|
|
446
|
+
to the HTTP server that would prevent the server to close.
|
|
447
|
+
_It is unlikely you will need to use this hook_,
|
|
448
|
+
use the [`onClose`](#onclose) for the most common case.
|
|
449
|
+
|
|
450
|
+
```js
|
|
451
|
+
// callback style
|
|
452
|
+
fastify.addHook('preClose', (done) => {
|
|
453
|
+
// Some code
|
|
454
|
+
done()
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
// or async/await style
|
|
458
|
+
fastify.addHook('preClose', async () => {
|
|
459
|
+
// Some async code
|
|
460
|
+
await removeSomeServerState()
|
|
461
|
+
})
|
|
462
|
+
```
|
|
463
|
+
|
|
437
464
|
### onRoute
|
|
438
465
|
<a id="on-route"></a>
|
|
439
466
|
|
|
440
|
-
Triggered when a new route is registered. Listeners are passed a `routeOptions`
|
|
467
|
+
Triggered when a new route is registered. Listeners are passed a [`routeOptions`](./Routes.md#routes-options)
|
|
441
468
|
object as the sole parameter. The interface is synchronous, and, as such, the
|
|
442
469
|
listeners are not passed a callback. This hook is encapsulated.
|
|
443
470
|
|
|
@@ -655,6 +682,12 @@ fastify.route({
|
|
|
655
682
|
// This hook will always be executed after the shared `onRequest` hooks
|
|
656
683
|
done()
|
|
657
684
|
},
|
|
685
|
+
// // Example with an async hook. All hooks support this syntax
|
|
686
|
+
//
|
|
687
|
+
// onRequest: async function (request, reply) {
|
|
688
|
+
// // This hook will always be executed after the shared `onRequest` hooks
|
|
689
|
+
// await ...
|
|
690
|
+
// }
|
|
658
691
|
onResponse: function (request, reply, done) {
|
|
659
692
|
// this hook will always be executed after the shared `onResponse` hooks
|
|
660
693
|
done()
|
|
@@ -728,7 +761,7 @@ fastify.get('/me/is-admin', async function (req, reply) {
|
|
|
728
761
|
```
|
|
729
762
|
|
|
730
763
|
Note that `.authenticatedUser` could actually be any property name
|
|
731
|
-
|
|
764
|
+
chosen by yourself. Using your own custom property prevents you
|
|
732
765
|
from mutating existing properties, which
|
|
733
766
|
would be a dangerous and destructive operation. So be careful and
|
|
734
767
|
make sure your property is entirely new, also using this approach
|
|
@@ -774,7 +807,7 @@ initialization of the tracking package, in the typical "require instrumentation
|
|
|
774
807
|
tools first" fashion.
|
|
775
808
|
|
|
776
809
|
```js
|
|
777
|
-
const tracer = /* retrieved from
|
|
810
|
+
const tracer = /* retrieved from elsewhere in the package */
|
|
778
811
|
const dc = require('diagnostics_channel')
|
|
779
812
|
const channel = dc.channel('fastify.initialization')
|
|
780
813
|
const spans = new WeakMap()
|
package/docs/Reference/Reply.md
CHANGED
|
@@ -243,7 +243,7 @@ reply.trailer('server-timing', function() {
|
|
|
243
243
|
})
|
|
244
244
|
|
|
245
245
|
const { createHash } = require('crypto')
|
|
246
|
-
// trailer function also
|
|
246
|
+
// trailer function also receive two argument
|
|
247
247
|
// @param {object} reply fastify reply
|
|
248
248
|
// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent
|
|
249
249
|
// @param {function} done callback to set trailer value
|
|
@@ -396,7 +396,7 @@ The function returned (a.k.a. _serialization function_) returned is compiled
|
|
|
396
396
|
by using the provided `SerializerCompiler`. Also this is cached by using
|
|
397
397
|
a `WeakMap` for reducing compilation calls.
|
|
398
398
|
|
|
399
|
-
The optional
|
|
399
|
+
The optional parameters `httpStatus` and `contentType`, if provided,
|
|
400
400
|
are forwarded directly to the `SerializerCompiler`, so it can be used
|
|
401
401
|
to compile the serialization function if a custom `SerializerCompiler` is used.
|
|
402
402
|
|
package/docs/Reference/Routes.md
CHANGED
|
@@ -78,7 +78,7 @@ fastify.route(options)
|
|
|
78
78
|
when a response has been sent, so you will not be able to send more data to
|
|
79
79
|
the client. It could also be an array of functions.
|
|
80
80
|
* `onTimeout(request, reply, done)`: a [function](./Hooks.md#ontimeout) called
|
|
81
|
-
when a request is timed out and the HTTP socket has been
|
|
81
|
+
when a request is timed out and the HTTP socket has been hung up.
|
|
82
82
|
* `onError(request, reply, error, done)`: a [function](./Hooks.md#onerror)
|
|
83
83
|
called when an Error is thrown or sent to the client by the route handler.
|
|
84
84
|
* `handler(request, reply)`: the function that will handle this request. The
|
|
@@ -219,7 +219,7 @@ fastify.get('/', opts)
|
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
> Note: if the handler is specified in both the `options` and as the third
|
|
222
|
-
> parameter to the shortcut method then throws duplicate `handler` error.
|
|
222
|
+
> parameter to the shortcut method then throws a duplicate `handler` error.
|
|
223
223
|
|
|
224
224
|
### Url building
|
|
225
225
|
<a id="url-building"></a>
|
|
@@ -290,6 +290,17 @@ fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', function (request, r
|
|
|
290
290
|
In this case as parameter separator it is possible to use whatever character is
|
|
291
291
|
not matched by the regular expression.
|
|
292
292
|
|
|
293
|
+
The last parameter can be made optional if you add a question mark ("?") to the
|
|
294
|
+
end of the parameters name.
|
|
295
|
+
```js
|
|
296
|
+
fastify.get('/example/posts/:id?', function (request, reply) {
|
|
297
|
+
const { id } = request.params;
|
|
298
|
+
// your code here
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
In this case you can request `/example/posts` as well as `/example/posts/1`.
|
|
302
|
+
The optional param will be undefined if not specified.
|
|
303
|
+
|
|
293
304
|
Having a route with multiple parameters may negatively affect performance, so
|
|
294
305
|
prefer a single parameter approach whenever possible, especially on routes that
|
|
295
306
|
are on the hot path of your application. If you are interested in how we handle
|
package/docs/Reference/Server.md
CHANGED
|
@@ -916,9 +916,25 @@ fastify.ready().then(() => {
|
|
|
916
916
|
|
|
917
917
|
Starts the server and internally waits for the `.ready()` event. The signature
|
|
918
918
|
is `.listen([options][, callback])`. Both the `options` object and the
|
|
919
|
-
`callback` parameters
|
|
920
|
-
core](https://nodejs.org/api/net.html#serverlistenoptions-callback)
|
|
921
|
-
|
|
919
|
+
`callback` parameters extend the [Node.js
|
|
920
|
+
core](https://nodejs.org/api/net.html#serverlistenoptions-callback) options
|
|
921
|
+
object. Thus, all core options are available with the following additional
|
|
922
|
+
Fastify specific options:
|
|
923
|
+
|
|
924
|
+
### `listenTextResolver`
|
|
925
|
+
<a id="listen-text-resolver"></a>
|
|
926
|
+
|
|
927
|
+
Set an optional resolver for the text to log after server has been successfully
|
|
928
|
+
started.
|
|
929
|
+
It is possible to override the default `Server listening at [address]` log
|
|
930
|
+
entry using this option.
|
|
931
|
+
|
|
932
|
+
```js
|
|
933
|
+
server.listen({
|
|
934
|
+
port: 9080,
|
|
935
|
+
listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }
|
|
936
|
+
})
|
|
937
|
+
```
|
|
922
938
|
|
|
923
939
|
By default, the server will listen on the address(es) resolved by `localhost`
|
|
924
940
|
when no specific host is provided. If listening on any available interface is
|
|
@@ -170,7 +170,7 @@ function plugin1(fastify: FastifyInstance, _opts, done): void {
|
|
|
170
170
|
})
|
|
171
171
|
}
|
|
172
172
|
}, (req) => {
|
|
173
|
-
// it doesn't
|
|
173
|
+
// it doesn't work! in a new scope needs to call `withTypeProvider` again
|
|
174
174
|
const { x, y, z } = req.body
|
|
175
175
|
});
|
|
176
176
|
done()
|
|
@@ -186,7 +186,7 @@ Serialization](./Validation-and-Serialization.md) documentation for more info.
|
|
|
186
186
|
Also it has the advantage to use the defined type within your handlers
|
|
187
187
|
(including pre-validation, etc.).
|
|
188
188
|
|
|
189
|
-
Here are some options how to achieve this.
|
|
189
|
+
Here are some options on how to achieve this.
|
|
190
190
|
|
|
191
191
|
#### Fastify Type Providers
|
|
192
192
|
|
|
@@ -1307,10 +1307,10 @@ types defined in this section are used under-the-hood by the Fastify instance
|
|
|
1307
1307
|
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L105)
|
|
1308
1308
|
|
|
1309
1309
|
A type declaration for the route handler methods. Has two arguments, `request`
|
|
1310
|
-
and `reply` which are typed by `FastifyRequest` and `FastifyReply`
|
|
1310
|
+
and `reply` which are typed by `FastifyRequest` and `FastifyReply` respectively.
|
|
1311
1311
|
The generics parameters are passed through to these arguments. The method
|
|
1312
1312
|
returns either `void` or `Promise<any>` for synchronous and asynchronous
|
|
1313
|
-
handlers
|
|
1313
|
+
handlers respectively.
|
|
1314
1314
|
|
|
1315
1315
|
##### fastify.RouteOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
|
1316
1316
|
|
package/docs/index.md
CHANGED
|
@@ -7,8 +7,8 @@ The documentation for Fastify is split into two categories:
|
|
|
7
7
|
|
|
8
8
|
The reference documentation utilizes a very formal style in an effort to document
|
|
9
9
|
Fastify's API and implementation details thoroughly for the developer who needs
|
|
10
|
-
such. The guides category utilizes an informal
|
|
11
|
-
introduce newcomers to core
|
|
10
|
+
such. The guides category utilizes an informal educational style as a means to
|
|
11
|
+
introduce newcomers to core and advanced Fastify concepts.
|
|
12
12
|
|
|
13
13
|
## Where To Start
|
|
14
14
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fastify = require('../../fastify')({
|
|
4
|
+
logger: false
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
const jsonParser = require('fast-json-body')
|
|
8
|
+
const querystring = require('querystring')
|
|
9
|
+
|
|
10
|
+
// Handled by fastify
|
|
11
|
+
// curl -X POST -d '{"hello":"world"}' -H'Content-type: application/json' http://localhost:3000/
|
|
12
|
+
|
|
13
|
+
// curl -X POST -d '{"hello":"world"}' -H'Content-type: application/jsoff' http://localhost:3000/
|
|
14
|
+
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {
|
|
15
|
+
jsonParser(payload, function (err, body) {
|
|
16
|
+
done(err, body)
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// curl -X POST -d 'hello=world' -H'Content-type: application/x-www-form-urlencoded' http://localhost:3000/
|
|
21
|
+
fastify.addContentTypeParser('application/x-www-form-urlencoded', function (request, payload, done) {
|
|
22
|
+
let body = ''
|
|
23
|
+
payload.on('data', function (data) {
|
|
24
|
+
body += data
|
|
25
|
+
})
|
|
26
|
+
payload.on('end', function () {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = querystring.parse(body)
|
|
29
|
+
done(null, parsed)
|
|
30
|
+
} catch (e) {
|
|
31
|
+
done(e)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
payload.on('error', done)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// curl -X POST -d '{"hello":"world"}' -H'Content-type: application/vnd.custom+json' http://localhost:3000/
|
|
38
|
+
fastify.addContentTypeParser(/^application\/.+\+json$/, { parseAs: 'string' }, fastify.getDefaultJsonParser('error', 'ignore'))
|
|
39
|
+
|
|
40
|
+
fastify
|
|
41
|
+
.post('/', function (req, reply) {
|
|
42
|
+
reply.send(req.body)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
fastify.listen({ port: 3000 }, (err, address) => {
|
|
46
|
+
if (err) throw err
|
|
47
|
+
})
|