fastify 4.0.2 → 4.2.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/.eslintrc +1 -0
- package/README.md +3 -3
- package/docs/Guides/Database.md +5 -5
- package/docs/Guides/Delay-Accepting-Requests.md +1 -1
- package/docs/Guides/Ecosystem.md +13 -0
- package/docs/Guides/Migration-Guide-V4.md +58 -2
- package/docs/Guides/Serverless.md +23 -10
- package/docs/Reference/Hooks.md +52 -0
- package/docs/Reference/LTS.md +2 -2
- package/docs/Reference/Plugins.md +1 -1
- package/docs/Reference/Server.md +1 -1
- package/docs/Reference/Type-Providers.md +4 -3
- package/docs/Reference/TypeScript.md +38 -25
- package/docs/Reference/Validation-and-Serialization.md +11 -0
- package/docs/index.md +1 -1
- package/fastify.d.ts +3 -3
- package/fastify.js +19 -19
- package/integration/server.js +27 -0
- package/integration/test.sh +23 -0
- package/lib/context.js +5 -2
- package/lib/error-serializer.js +173 -8
- package/lib/handleRequest.js +1 -1
- package/lib/reply.js +2 -0
- package/lib/route.js +39 -29
- package/lib/server.js +9 -1
- package/lib/symbols.js +2 -1
- package/lib/validation.js +2 -0
- package/lib/wrapThenable.js +8 -3
- package/package.json +6 -6
- package/test/404s.test.js +2 -2
- package/test/build/error-serializer.test.js +6 -1
- package/test/hooks.test.js +21 -0
- package/test/internals/reply.test.js +12 -0
- package/test/listen.test.js +16 -2
- package/test/pretty-print.test.js +3 -3
- package/test/reply-error.test.js +1 -1
- package/test/schema-feature.test.js +2 -2
- package/test/stream.test.js +73 -0
- package/test/types/fastify.test-d.ts +12 -1
- package/test/types/instance.test-d.ts +1 -1
- package/test/types/register.test-d.ts +77 -2
- package/test/types/request.test-d.ts +8 -4
- package/test/types/type-provider.test-d.ts +11 -2
- package/test/validation-error-handling.test.js +32 -0
- package/types/register.d.ts +9 -7
- package/types/route.d.ts +10 -12
- package/types/schema.d.ts +1 -1
- package/types/type-provider.d.ts +12 -5
package/.eslintrc
CHANGED
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ developer experience with the least overhead and a powerful plugin architecture.
|
|
|
56
56
|
It is inspired by Hapi and Express and as far as we know, it is one of the
|
|
57
57
|
fastest web frameworks in town.
|
|
58
58
|
|
|
59
|
-
This branch refers to the
|
|
59
|
+
This branch refers to the Fastify v4 release. Check out the
|
|
60
60
|
[v3.x](https://github.com/fastify/fastify/tree/v3.x) branch for v3.
|
|
61
61
|
|
|
62
62
|
### Quick start
|
|
@@ -104,11 +104,11 @@ project as a dependency:
|
|
|
104
104
|
|
|
105
105
|
Install with npm:
|
|
106
106
|
```sh
|
|
107
|
-
npm i fastify
|
|
107
|
+
npm i fastify
|
|
108
108
|
```
|
|
109
109
|
Install with yarn:
|
|
110
110
|
```sh
|
|
111
|
-
yarn add fastify
|
|
111
|
+
yarn add fastify
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
### Example
|
package/docs/Guides/Database.md
CHANGED
|
@@ -37,7 +37,7 @@ fastify.get('/user/:id', function(req, reply) {
|
|
|
37
37
|
)
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
fastify.listen(3000, err => {
|
|
40
|
+
fastify.listen({ port: 3000 }, err => {
|
|
41
41
|
if (err) throw err
|
|
42
42
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
43
43
|
})
|
|
@@ -64,7 +64,7 @@ fastify.get('/user/:id', function (req, reply) {
|
|
|
64
64
|
)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
fastify.listen(3000, err => {
|
|
67
|
+
fastify.listen({ port: 3000 }, err => {
|
|
68
68
|
if (err) throw err
|
|
69
69
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
70
70
|
})
|
|
@@ -98,7 +98,7 @@ fastify.post('/foo', function (req, reply) {
|
|
|
98
98
|
})
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
-
fastify.listen(3000, err => {
|
|
101
|
+
fastify.listen({ port: 3000 }, err => {
|
|
102
102
|
if (err) throw err
|
|
103
103
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
104
104
|
})
|
|
@@ -145,7 +145,7 @@ fastify.get('/user/:id', function (req, reply) {
|
|
|
145
145
|
})
|
|
146
146
|
})
|
|
147
147
|
|
|
148
|
-
fastify.listen(3000, err => {
|
|
148
|
+
fastify.listen({ port: 3000 }, err => {
|
|
149
149
|
if (err) throw err
|
|
150
150
|
})
|
|
151
151
|
```
|
|
@@ -172,7 +172,7 @@ fastify.post('/foo', async function (req, reply) {
|
|
|
172
172
|
return { status: 'ok' }
|
|
173
173
|
})
|
|
174
174
|
|
|
175
|
-
fastify.listen(3000, err => {
|
|
175
|
+
fastify.listen({ port: 3000 }, err => {
|
|
176
176
|
if (err) throw err
|
|
177
177
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
178
178
|
})
|
|
@@ -48,7 +48,7 @@ server (fewer resources allocated to a bound-to-fail task) and for the client
|
|
|
48
48
|
That will be achieved by wrapping into a custom plugin two main features:
|
|
49
49
|
|
|
50
50
|
1. the mechanism for authenticating with the provider
|
|
51
|
-
[decorating](../
|
|
51
|
+
[decorating](../Reference/Decorators.md) the `fastify` object with the
|
|
52
52
|
authentication key (`magicKey` from here onwards)
|
|
53
53
|
1. the mechanism for denying requests that would, otherwise, fail
|
|
54
54
|
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -132,9 +132,15 @@ section.
|
|
|
132
132
|
sampling process metrics.
|
|
133
133
|
- [`@dnlup/fastify-traps`](https://github.com/dnlup/fastify-traps) A plugin to
|
|
134
134
|
close the server gracefully on `SIGINT` and `SIGTERM` signals.
|
|
135
|
+
- [`@eropple/fastify-openapi3`](https://github.com/eropple/fastify-openapi3) Provides
|
|
136
|
+
easy, developer-friendly OpenAPI 3.1 specs + doc explorer based on your routes.
|
|
135
137
|
- [`@gquittet/graceful-server`](https://github.com/gquittet/graceful-server)
|
|
136
138
|
Tiny (~5k), Fast, KISS, and dependency-free Node.JS library to make your
|
|
137
139
|
Fastify API graceful.
|
|
140
|
+
- [`@h4ad/serverless-adapter`](https://github.com/H4ad/serverless-adapter)
|
|
141
|
+
Run REST APIs and other web applications using your existing Node.js
|
|
142
|
+
application framework (Express, Koa, Hapi and Fastify), on top of AWS Lambda,
|
|
143
|
+
Huawei and many other clouds.
|
|
138
144
|
- [`@immobiliarelabs/fastify-metrics`](https://github.com/immobiliare/fastify-metrics)
|
|
139
145
|
Minimalistic and opinionated plugin that collects usage/process metrics and
|
|
140
146
|
dispatches to [statsd](https://github.com/statsd/statsd).
|
|
@@ -327,6 +333,8 @@ section.
|
|
|
327
333
|
Kubernetes client plugin.
|
|
328
334
|
- [`fastify-language-parser`](https://github.com/lependu/fastify-language-parser)
|
|
329
335
|
Fastify plugin to parse request language.
|
|
336
|
+
- [`fastify-lcache`](https://github.com/denbon05/fastify-lcache)
|
|
337
|
+
Lightweight cache plugin
|
|
330
338
|
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from
|
|
331
339
|
a directory and inject the Fastify instance in each file.
|
|
332
340
|
- [`fastify-lured`](https://github.com/lependu/fastify-lured) Plugin to load lua
|
|
@@ -346,6 +354,9 @@ section.
|
|
|
346
354
|
minification and transformation of responses.
|
|
347
355
|
- [`fastify-mongo-memory`](https://github.com/chapuletta/fastify-mongo-memory)
|
|
348
356
|
Fastify MongoDB in Memory Plugin for testing support.
|
|
357
|
+
- [`fastify-mongodb-sanitizer`](https://github.com/KlemenKozelj/fastify-mongodb-sanitizer)
|
|
358
|
+
Fastify plugin that sanitizes client input to prevent
|
|
359
|
+
potential MongoDB query injection attacks.
|
|
349
360
|
- [`fastify-mongoose-api`](https://github.com/jeka-kiselyov/fastify-mongoose-api)
|
|
350
361
|
Fastify plugin to create REST API methods based on Mongoose MongoDB models.
|
|
351
362
|
- [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose)
|
|
@@ -475,6 +486,8 @@ section.
|
|
|
475
486
|
Events with `reply.sse( … )` to Fastify.
|
|
476
487
|
- [`fastify-sse-v2`](https://github.com/nodefactoryio/fastify-sse-v2) to provide
|
|
477
488
|
Server-Sent Events using Async Iterators (supports newer versions of Fastify).
|
|
489
|
+
- [`fastify-ssr-vite`](https://github.com/nineohnine/fastify-ssr-vite) A simple
|
|
490
|
+
plugin for setting up server side rendering with vite.
|
|
478
491
|
- [`fastify-stripe`](https://github.com/coopflow/fastify-stripe) Plugin to
|
|
479
492
|
initialize and encapsulate [Stripe
|
|
480
493
|
Node.js](https://github.com/stripe/stripe-node) instances in Fastify.
|
|
@@ -8,7 +8,39 @@ work after upgrading.
|
|
|
8
8
|
|
|
9
9
|
## Breaking Changes
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Error handling composition ([#3261](https://github.com/fastify/fastify/pull/3261))
|
|
12
|
+
|
|
13
|
+
When an error is thrown in a async error handler function,
|
|
14
|
+
the upper-level error handler is executed if set.
|
|
15
|
+
If there is not a upper-level error handler, the default will
|
|
16
|
+
be executed as it was previously.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
import Fastify from 'fastify'
|
|
20
|
+
|
|
21
|
+
const fastify = Fastify()
|
|
22
|
+
|
|
23
|
+
fastify.register(async fastify => {
|
|
24
|
+
fastify.setErrorHandler(async err => {
|
|
25
|
+
console.log(err.message) // 'kaboom'
|
|
26
|
+
throw new Error('caught')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
fastify.get('/encapsulated', async () => {
|
|
30
|
+
throw new Error('kaboom')
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
fastify.setErrorHandler(async err => {
|
|
35
|
+
console.log(err.message) // 'caught'
|
|
36
|
+
throw new Error('wrapped')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const res = await fastify.inject('/encapsulated')
|
|
40
|
+
console.log(res.json().message) // 'wrapped'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Deprecation of `app.use()` ([#3506](https://github.com/fastify/fastify/pull/3506))
|
|
12
44
|
|
|
13
45
|
Starting this version of Fastify, we have deprecated the use of `app.use()`. We
|
|
14
46
|
have decided not to support the use of middlewares. Both
|
|
@@ -16,12 +48,29 @@ have decided not to support the use of middlewares. Both
|
|
|
16
48
|
[`@fastify/express`](https://github.com/fastify/fastify-express) will still be
|
|
17
49
|
there and maintained. Use Fastify's [hooks](../Reference/Hooks.md) instead.
|
|
18
50
|
|
|
51
|
+
### `reply.res` moved to `reply.raw`
|
|
52
|
+
|
|
53
|
+
If you previously used the `reply.res` attribute to access the underlying Request
|
|
54
|
+
object you'll instead need to depend on `reply.raw`.
|
|
55
|
+
|
|
56
|
+
### Need to `return reply` to signal a "fork" of the promise chain
|
|
57
|
+
|
|
58
|
+
In some situations, like when a response is sent asynchronously or when you're
|
|
59
|
+
just not explicitly returning a response, you'll need to return the `reply`
|
|
60
|
+
argument from your router handler.
|
|
61
|
+
|
|
62
|
+
### `exposeHeadRoutes` true by default
|
|
63
|
+
|
|
64
|
+
Starting from v4, all the `GET` routes will create a sibling `HEAD` route.
|
|
65
|
+
You can revert this behaviour by setting the server's option `exposeHeadRoutes`
|
|
66
|
+
to `false`.
|
|
67
|
+
|
|
19
68
|
## Non Breaking Changes
|
|
20
69
|
|
|
21
70
|
### Change of schema for multiple types
|
|
22
71
|
|
|
23
72
|
|
|
24
|
-
Since
|
|
73
|
+
Since Fastify v4 has upgraded to Ajv v8. The "type" keywords with multiple types
|
|
25
74
|
(other than with "null") are prohibited. Read more
|
|
26
75
|
['here'](https://ajv.js.org/strict-mode.html#strict-types)
|
|
27
76
|
|
|
@@ -53,3 +102,10 @@ properties: {
|
|
|
53
102
|
}
|
|
54
103
|
}
|
|
55
104
|
```
|
|
105
|
+
|
|
106
|
+
### Add `reply.trailers` methods ([#3794](https://github.com/fastify/fastify/pull/3794))
|
|
107
|
+
|
|
108
|
+
Fastify now supports the [HTTP Trailer] response headers.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
[HTTP Trailer]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer
|
|
@@ -24,23 +24,31 @@ snippet of code.
|
|
|
24
24
|
|
|
25
25
|
### Contents
|
|
26
26
|
|
|
27
|
-
- [AWS
|
|
27
|
+
- [AWS](#aws)
|
|
28
28
|
- [Google Cloud Functions](#google-cloud-functions)
|
|
29
29
|
- [Google Cloud Run](#google-cloud-run)
|
|
30
30
|
- [Netlify Lambda](#netlify-lambda)
|
|
31
31
|
- [Vercel](#vercel)
|
|
32
32
|
|
|
33
|
-
## AWS
|
|
33
|
+
## AWS
|
|
34
|
+
|
|
35
|
+
To integrate with AWS, you have two choices of library:
|
|
36
|
+
|
|
37
|
+
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify)
|
|
38
|
+
which only adds API Gateway support but has heavy optimizations for fastify.
|
|
39
|
+
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter)
|
|
40
|
+
which is a little slower as it creates an HTTP request for each AWS event but
|
|
41
|
+
has support for more AWS services such as: AWS SQS, AWS SNS and others.
|
|
42
|
+
|
|
43
|
+
So you can decide which option is best for you, but you can test both libraries.
|
|
44
|
+
|
|
45
|
+
### Using @fastify/aws-lambda
|
|
34
46
|
|
|
35
47
|
The sample provided allows you to easily build serverless web
|
|
36
48
|
applications/services and RESTful APIs using Fastify on top of AWS Lambda and
|
|
37
49
|
Amazon API Gateway.
|
|
38
50
|
|
|
39
|
-
|
|
40
|
-
[@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify) is just one
|
|
41
|
-
possible way.*
|
|
42
|
-
|
|
43
|
-
### app.js
|
|
51
|
+
#### app.js
|
|
44
52
|
|
|
45
53
|
```js
|
|
46
54
|
const fastify = require('fastify');
|
|
@@ -71,7 +79,7 @@ When you execute your Fastify application like always, i.e. `node app.js` *(the
|
|
|
71
79
|
detection for this could be `require.main === module`)*, you can normally listen
|
|
72
80
|
to your port, so you can still run your Fastify function locally.
|
|
73
81
|
|
|
74
|
-
|
|
82
|
+
#### lambda.js
|
|
75
83
|
|
|
76
84
|
```js
|
|
77
85
|
const awsLambdaFastify = require('@fastify/aws-lambda')
|
|
@@ -99,14 +107,13 @@ signature to be used as a lambda `handler` function. This way all the incoming
|
|
|
99
107
|
events (API Gateway requests) are passed to the `proxy` function of
|
|
100
108
|
[@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify).
|
|
101
109
|
|
|
102
|
-
|
|
110
|
+
#### Example
|
|
103
111
|
|
|
104
112
|
An example deployable with
|
|
105
113
|
[claudia.js](https://claudiajs.com/tutorials/serverless-express.html) can be
|
|
106
114
|
found
|
|
107
115
|
[here](https://github.com/claudiajs/example-projects/tree/master/fastify-app-lambda).
|
|
108
116
|
|
|
109
|
-
|
|
110
117
|
### Considerations
|
|
111
118
|
|
|
112
119
|
- API Gateway does not support streams yet, so you are not able to handle
|
|
@@ -114,6 +121,12 @@ found
|
|
|
114
121
|
- API Gateway has a timeout of 29 seconds, so it is important to provide a reply
|
|
115
122
|
during this time.
|
|
116
123
|
|
|
124
|
+
#### Beyond API Gateway
|
|
125
|
+
|
|
126
|
+
If you need to integrate with more AWS services, take a look at
|
|
127
|
+
[@h4ad/serverless-adapter](https://viniciusl.com.br/serverless-adapter/docs/main/frameworks/fastify)
|
|
128
|
+
on Fastify to find out how to integrate.
|
|
129
|
+
|
|
117
130
|
## Google Cloud Functions
|
|
118
131
|
|
|
119
132
|
### Creation of Fastify instance
|
package/docs/Reference/Hooks.md
CHANGED
|
@@ -28,6 +28,7 @@ are Request/Reply hooks and application hooks:
|
|
|
28
28
|
- [onRegister](#onregister)
|
|
29
29
|
- [Scope](#scope)
|
|
30
30
|
- [Route level hooks](#route-level-hooks)
|
|
31
|
+
- [Using Hooks to Inject Custom Properties](#using-hooks-to-inject-custom-properties)
|
|
31
32
|
- [Diagnostics Channel Hooks](#diagnostics-channel-hooks)
|
|
32
33
|
|
|
33
34
|
**Notice:** the `done` callback is not available when using `async`/`await` or
|
|
@@ -649,6 +650,57 @@ fastify.route({
|
|
|
649
650
|
|
|
650
651
|
**Note**: both options also accept an array of functions.
|
|
651
652
|
|
|
653
|
+
## Using Hooks to Inject Custom Properties
|
|
654
|
+
<a id="using-hooks-to-inject-custom-properties"></a>
|
|
655
|
+
|
|
656
|
+
You can use a hook to inject custom properties into incoming requests.
|
|
657
|
+
This is useful for reusing processed data from hooks in controllers.
|
|
658
|
+
|
|
659
|
+
A very common use case is, for example, checking user authentication based
|
|
660
|
+
on their token and then storing their recovered data into
|
|
661
|
+
the [Request](./Request.md) instance. This way, your controllers can read it
|
|
662
|
+
easily with `request.authenticatedUser` or whatever you want to call it.
|
|
663
|
+
That's how it might look like:
|
|
664
|
+
|
|
665
|
+
```js
|
|
666
|
+
fastify.addHook('preParsing', async (request) => {
|
|
667
|
+
request.authenticatedUser = {
|
|
668
|
+
id: 42,
|
|
669
|
+
name: 'Jane Doe',
|
|
670
|
+
role: 'admin'
|
|
671
|
+
}
|
|
672
|
+
})
|
|
673
|
+
|
|
674
|
+
fastify.get('/me/is-admin', async function (req, reply) {
|
|
675
|
+
return { isAdmin: req.authenticatedUser?.role === 'admin' || false }
|
|
676
|
+
})
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Note that `.authenticatedUser` could actually be any property name
|
|
680
|
+
choosen by yourself. Using your own custom property prevents you
|
|
681
|
+
from mutating existing properties, which
|
|
682
|
+
would be a dangerous and destructive operation. So be careful and
|
|
683
|
+
make sure your property is entirely new, also using this approach
|
|
684
|
+
only for very specific and small cases like this example.
|
|
685
|
+
|
|
686
|
+
Regarding TypeScript in this example, you'd need to update the
|
|
687
|
+
`FastifyRequest` core interface to include your new property typing
|
|
688
|
+
(for more about it, see [TypeScript](./TypeScript.md) page), like:
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
interface AuthenticatedUser { /* ... */ }
|
|
692
|
+
|
|
693
|
+
declare module 'fastify' {
|
|
694
|
+
export interface FastifyRequest {
|
|
695
|
+
authenticatedUser?: AuthenticatedUser;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Although this is a very pragmatic approach, if you're trying to do
|
|
701
|
+
something more complex that changes these core objects, then
|
|
702
|
+
consider creating a custom [Plugin](./Plugins.md) instead.
|
|
703
|
+
|
|
652
704
|
## Diagnostics Channel Hooks
|
|
653
705
|
|
|
654
706
|
> **Note:** The `diagnostics_channel` is currently experimental on Node.js, so
|
package/docs/Reference/LTS.md
CHANGED
|
@@ -47,8 +47,8 @@ A "month" is defined as 30 consecutive days.
|
|
|
47
47
|
| :------ | :----------- | :-------------- | :------------------- |
|
|
48
48
|
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 |
|
|
49
49
|
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 |
|
|
50
|
-
| 3.0.0 | 2020-07-07 |
|
|
51
|
-
| 4.0.0 |
|
|
50
|
+
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 |
|
|
51
|
+
| 4.0.0 | 2022-06-08 | TBD | 14, 16, 18 |
|
|
52
52
|
|
|
53
53
|
### CI tested operating systems
|
|
54
54
|
<a id="supported-os"></a>
|
|
@@ -13,7 +13,7 @@ way we create a *directed acyclic graph* (DAG) and we will not have issues
|
|
|
13
13
|
caused by cross dependencies.
|
|
14
14
|
|
|
15
15
|
You may have already seen in the [Getting
|
|
16
|
-
Started](
|
|
16
|
+
Started](../Guides/Getting-Started.md#your-first-plugin) guide how easy it is
|
|
17
17
|
to use this API:
|
|
18
18
|
```
|
|
19
19
|
fastify.register(plugin, [options])
|
package/docs/Reference/Server.md
CHANGED
|
@@ -1278,7 +1278,7 @@ const fastify = Fastify({
|
|
|
1278
1278
|
*/
|
|
1279
1279
|
bucket: function factory (parentSchemas) {
|
|
1280
1280
|
return {
|
|
1281
|
-
|
|
1281
|
+
add (inputSchema) {
|
|
1282
1282
|
// This function must store the schema added by the user.
|
|
1283
1283
|
// This function is invoked when `fastify.addSchema()` is called.
|
|
1284
1284
|
},
|
|
@@ -30,11 +30,11 @@ $ npm i @fastify/type-provider-json-schema-to-ts
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
|
-
import {
|
|
33
|
+
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
|
|
34
34
|
|
|
35
35
|
import fastify from 'fastify'
|
|
36
36
|
|
|
37
|
-
const server = fastify().withTypeProvider<
|
|
37
|
+
const server = fastify().withTypeProvider<JsonSchemaToTsProvider>()
|
|
38
38
|
|
|
39
39
|
server.get('/route', {
|
|
40
40
|
schema: {
|
|
@@ -65,7 +65,8 @@ $ npm i @fastify/type-provider-typebox
|
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
|
-
import { TypeBoxTypeProvider
|
|
68
|
+
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
69
|
+
import { Type } from '@sinclair/typebox'
|
|
69
70
|
|
|
70
71
|
import fastify from 'fastify'
|
|
71
72
|
|
|
@@ -199,17 +199,18 @@ Below is how to setup schema validation using vanilla `typebox` and
|
|
|
199
199
|
#### typebox
|
|
200
200
|
|
|
201
201
|
A useful library for building types and a schema at once is
|
|
202
|
-
[typebox](https://www.npmjs.com/package/@sinclair/typebox)
|
|
203
|
-
|
|
204
|
-
you
|
|
202
|
+
[typebox](https://www.npmjs.com/package/@sinclair/typebox) along with
|
|
203
|
+
[fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox).
|
|
204
|
+
With typebox you define your schema within your code and use them
|
|
205
|
+
directly as types or schemas as you need them.
|
|
205
206
|
|
|
206
207
|
When you want to use it for validation of some payload in a fastify route you
|
|
207
208
|
can do it as follows:
|
|
208
209
|
|
|
209
|
-
1. Install `typebox` in your project.
|
|
210
|
+
1. Install `typebox` and `fastify-type-provider-typebox` in your project.
|
|
210
211
|
|
|
211
212
|
```bash
|
|
212
|
-
npm i @sinclair/typebox
|
|
213
|
+
npm i @sinclair/typebox @fastify/type-provider-typebox
|
|
213
214
|
```
|
|
214
215
|
|
|
215
216
|
2. Define the schema you need with `Type` and create the respective type with
|
|
@@ -218,40 +219,52 @@ can do it as follows:
|
|
|
218
219
|
```typescript
|
|
219
220
|
import { Static, Type } from '@sinclair/typebox'
|
|
220
221
|
|
|
221
|
-
const User = Type.Object({
|
|
222
|
+
export const User = Type.Object({
|
|
222
223
|
name: Type.String(),
|
|
223
|
-
mail: Type.Optional(Type.String({ format:
|
|
224
|
-
})
|
|
225
|
-
|
|
224
|
+
mail: Type.Optional(Type.String({ format: 'email' })),
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
export type UserType = Static<typeof User>
|
|
226
228
|
```
|
|
227
229
|
|
|
228
230
|
3. Use the defined type and schema during the definition of your route
|
|
229
231
|
|
|
230
232
|
```typescript
|
|
231
|
-
|
|
233
|
+
import Fastify from 'fastify'
|
|
234
|
+
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
235
|
+
// ...
|
|
236
|
+
|
|
237
|
+
const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
|
|
232
238
|
|
|
233
|
-
app.post<{ Body: UserType
|
|
234
|
-
|
|
239
|
+
app.post<{ Body: UserType, Reply: UserType }>(
|
|
240
|
+
'/',
|
|
235
241
|
{
|
|
236
242
|
schema: {
|
|
237
243
|
body: User,
|
|
238
244
|
response: {
|
|
239
|
-
200: User
|
|
245
|
+
200: User
|
|
240
246
|
},
|
|
241
247
|
},
|
|
242
248
|
},
|
|
243
249
|
(request, reply) => {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
// The `name` and `mail` types are automatically inferred
|
|
251
|
+
const { name, mail } = request.body;
|
|
252
|
+
reply.status(200).send({ name, mail });
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Note** For Ajv version 7 and above is required to use the `ajvTypeBoxPlugin`:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import Fastify from 'fastify'
|
|
261
|
+
import { ajvTypeBoxPlugin, TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
262
|
+
|
|
263
|
+
const fastify = Fastify({
|
|
264
|
+
ajv: {
|
|
265
|
+
plugins: [ajvTypeBoxPlugin]
|
|
253
266
|
}
|
|
254
|
-
)
|
|
267
|
+
}).withTypeProvider<TypeBoxTypeProvider>()
|
|
255
268
|
```
|
|
256
269
|
|
|
257
270
|
#### Schemas in JSON Files
|
|
@@ -1359,7 +1372,7 @@ A method for checking the existence of a type parser of a certain content type
|
|
|
1359
1372
|
|
|
1360
1373
|
##### fastify.FastifyError
|
|
1361
1374
|
|
|
1362
|
-
[src](https://github.com/fastify/fastify/blob/main/
|
|
1375
|
+
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179)
|
|
1363
1376
|
|
|
1364
1377
|
FastifyError is a custom error object that includes status code and validation
|
|
1365
1378
|
results.
|
|
@@ -1369,7 +1382,7 @@ properties: `statusCode: number` and `validation: ValiationResult[]`.
|
|
|
1369
1382
|
|
|
1370
1383
|
##### fastify.ValidationResult
|
|
1371
1384
|
|
|
1372
|
-
[src](https://github.com/fastify/fastify/blob/main/
|
|
1385
|
+
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184)
|
|
1373
1386
|
|
|
1374
1387
|
The route validation internally relies upon Ajv, which is a high-performance
|
|
1375
1388
|
JSON schema validator.
|
|
@@ -484,6 +484,17 @@ fastify.post('/the/url', {
|
|
|
484
484
|
}, handler)
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
+
##### .statusCode property
|
|
488
|
+
|
|
489
|
+
All validation errors will be added a `.statusCode` property set to `400`. This guarantees
|
|
490
|
+
that the default error handler will set the status code of the response to `400`.
|
|
491
|
+
|
|
492
|
+
```js
|
|
493
|
+
fastify.setErrorHandler(function (error, request, reply) {
|
|
494
|
+
request.log.error(error, `This error has status code ${error.statusCode}`)
|
|
495
|
+
reply.status(error.statusCode).send(error)
|
|
496
|
+
})
|
|
497
|
+
```
|
|
487
498
|
|
|
488
499
|
##### Validation messages with other validation libraries
|
|
489
500
|
|
package/docs/index.md
CHANGED
|
@@ -16,7 +16,7 @@ Complete newcomers to Fastify should first read our [Getting
|
|
|
16
16
|
Started](./Guides/Getting-Started.md) guide.
|
|
17
17
|
|
|
18
18
|
Developers experienced with Fastify should consult the [reference
|
|
19
|
-
documentation](./Reference/
|
|
19
|
+
documentation](./Reference/Index.md) directly to find the topic they are seeking
|
|
20
20
|
more information about.
|
|
21
21
|
|
|
22
22
|
## Additional Documentation
|
package/fastify.d.ts
CHANGED
|
@@ -146,7 +146,7 @@ export type FastifyServerOptions<
|
|
|
146
146
|
},
|
|
147
147
|
schemaController?: {
|
|
148
148
|
bucket?: (parentSchemas?: unknown) => {
|
|
149
|
-
|
|
149
|
+
add(schema: unknown): FastifyInstance;
|
|
150
150
|
getSchema(schemaId: string): unknown;
|
|
151
151
|
getSchemas(): Record<string, unknown>;
|
|
152
152
|
};
|
|
@@ -183,10 +183,10 @@ declare module '@fastify/error' {
|
|
|
183
183
|
|
|
184
184
|
export interface ValidationResult {
|
|
185
185
|
keyword: string;
|
|
186
|
-
|
|
186
|
+
instancePath: string;
|
|
187
187
|
schemaPath: string;
|
|
188
188
|
params: Record<string, string | string[]>;
|
|
189
|
-
message
|
|
189
|
+
message?: string;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/* Export all additional types */
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '4.0
|
|
3
|
+
const VERSION = '4.2.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
@@ -237,35 +237,35 @@ function fastify (options) {
|
|
|
237
237
|
getDefaultRoute: router.getDefaultRoute.bind(router),
|
|
238
238
|
setDefaultRoute: router.setDefaultRoute.bind(router),
|
|
239
239
|
// routes shorthand methods
|
|
240
|
-
delete: function _delete (url,
|
|
241
|
-
return router.prepareRoute.call(this, 'DELETE', url,
|
|
240
|
+
delete: function _delete (url, options, handler) {
|
|
241
|
+
return router.prepareRoute.call(this, { method: 'DELETE', url, options, handler })
|
|
242
242
|
},
|
|
243
|
-
get: function _get (url,
|
|
244
|
-
return router.prepareRoute.call(this, 'GET', url,
|
|
243
|
+
get: function _get (url, options, handler) {
|
|
244
|
+
return router.prepareRoute.call(this, { method: 'GET', url, options, handler })
|
|
245
245
|
},
|
|
246
|
-
head: function _head (url,
|
|
247
|
-
return router.prepareRoute.call(this, 'HEAD', url,
|
|
246
|
+
head: function _head (url, options, handler) {
|
|
247
|
+
return router.prepareRoute.call(this, { method: 'HEAD', url, options, handler })
|
|
248
248
|
},
|
|
249
|
-
patch: function _patch (url,
|
|
250
|
-
return router.prepareRoute.call(this, 'PATCH', url,
|
|
249
|
+
patch: function _patch (url, options, handler) {
|
|
250
|
+
return router.prepareRoute.call(this, { method: 'PATCH', url, options, handler })
|
|
251
251
|
},
|
|
252
|
-
post: function _post (url,
|
|
253
|
-
return router.prepareRoute.call(this, 'POST', url,
|
|
252
|
+
post: function _post (url, options, handler) {
|
|
253
|
+
return router.prepareRoute.call(this, { method: 'POST', url, options, handler })
|
|
254
254
|
},
|
|
255
|
-
put: function _put (url,
|
|
256
|
-
return router.prepareRoute.call(this, 'PUT', url,
|
|
255
|
+
put: function _put (url, options, handler) {
|
|
256
|
+
return router.prepareRoute.call(this, { method: 'PUT', url, options, handler })
|
|
257
257
|
},
|
|
258
|
-
options: function _options (url,
|
|
259
|
-
return router.prepareRoute.call(this, 'OPTIONS', url,
|
|
258
|
+
options: function _options (url, options, handler) {
|
|
259
|
+
return router.prepareRoute.call(this, { method: 'OPTIONS', url, options, handler })
|
|
260
260
|
},
|
|
261
|
-
all: function _all (url,
|
|
262
|
-
return router.prepareRoute.call(this, supportedMethods, url,
|
|
261
|
+
all: function _all (url, options, handler) {
|
|
262
|
+
return router.prepareRoute.call(this, { method: supportedMethods, url, options, handler })
|
|
263
263
|
},
|
|
264
264
|
// extended route
|
|
265
|
-
route: function _route (
|
|
265
|
+
route: function _route (options) {
|
|
266
266
|
// we need the fastify object that we are producing so we apply a lazy loading of the function,
|
|
267
267
|
// otherwise we should bind it after the declaration
|
|
268
|
-
return router.route.call(this,
|
|
268
|
+
return router.route.call(this, { options })
|
|
269
269
|
},
|
|
270
270
|
// expose logger instance
|
|
271
271
|
log: logger,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const Fastify = require('../fastify')
|
|
2
|
+
|
|
3
|
+
const fastify = Fastify()
|
|
4
|
+
|
|
5
|
+
fastify.listen({
|
|
6
|
+
host: '::',
|
|
7
|
+
port: 3000
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
fastify.get('/', async function (request, reply) {
|
|
11
|
+
reply.code(200).send({ data: 'home page' })
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
fastify.post('/post/:id', async function (request, reply) {
|
|
15
|
+
const { id } = request.params
|
|
16
|
+
reply.code(201).send({ data: `${id}` })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
fastify.put('/put/:id', async function (request, reply) {
|
|
20
|
+
const { id } = request.params
|
|
21
|
+
reply.code(200).send({ data: `${id}` })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
fastify.delete('/delete/:id', async function (request, reply) {
|
|
25
|
+
const { id } = request.params
|
|
26
|
+
reply.code(204).send({ data: `${id}` })
|
|
27
|
+
})
|