fastify 3.26.0 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +49 -35
- package/docs/Guides/Ecosystem.md +2 -1
- package/docs/Guides/Prototype-Poisoning.md +3 -3
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +8 -1
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Reply.md +23 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +17 -10
- package/docs/Reference/Server.md +98 -63
- package/docs/Reference/TypeScript.md +11 -13
- package/docs/Reference/Validation-and-Serialization.md +32 -54
- package/docs/Type-Providers.md +257 -0
- package/examples/hooks.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/fastify.d.ts +36 -22
- package/fastify.js +72 -53
- package/lib/configValidator.js +902 -1023
- package/lib/contentTypeParser.js +6 -16
- package/lib/context.js +36 -10
- package/lib/decorate.js +5 -3
- package/lib/error-handler.js +158 -0
- package/lib/error-serializer.js +257 -0
- package/lib/errors.js +49 -10
- package/lib/fourOhFour.js +31 -20
- package/lib/handleRequest.js +10 -13
- package/lib/hooks.js +14 -9
- package/lib/noop-set.js +10 -0
- package/lib/pluginOverride.js +0 -3
- package/lib/pluginUtils.js +3 -2
- package/lib/reply.js +44 -163
- package/lib/request.js +13 -10
- package/lib/route.js +158 -139
- package/lib/schema-controller.js +3 -3
- package/lib/schemas.js +27 -1
- package/lib/server.js +219 -116
- package/lib/symbols.js +6 -4
- package/lib/validation.js +2 -1
- package/lib/warnings.js +2 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +40 -45
- package/test/404s.test.js +265 -108
- package/test/500s.test.js +2 -2
- package/test/async-await.test.js +15 -71
- package/test/close.test.js +39 -1
- package/test/content-parser.test.js +32 -0
- package/test/context-config.test.js +56 -4
- package/test/custom-http-server.test.js +14 -7
- package/test/custom-parser-async.test.js +0 -65
- package/test/custom-parser.test.js +54 -121
- package/test/decorator.test.js +1 -3
- package/test/delete.test.js +5 -5
- package/test/encapsulated-error-handler.test.js +50 -0
- package/test/esm/index.test.js +0 -14
- package/test/fastify-instance.test.js +4 -4
- package/test/fluent-schema.test.js +4 -4
- package/test/get.test.js +3 -3
- package/test/helper.js +18 -3
- package/test/hooks-async.test.js +14 -47
- package/test/hooks.on-ready.test.js +9 -4
- package/test/hooks.test.js +58 -99
- package/test/http2/closing.test.js +5 -11
- package/test/http2/unknown-http-method.test.js +3 -9
- package/test/https/custom-https-server.test.js +12 -6
- package/test/inject.test.js +1 -1
- package/test/input-validation.js +2 -2
- package/test/internals/all.test.js +2 -2
- package/test/internals/contentTypeParser.test.js +4 -4
- package/test/internals/handleRequest.test.js +9 -46
- package/test/internals/initialConfig.test.js +33 -12
- package/test/internals/logger.test.js +1 -1
- package/test/internals/reply.test.js +245 -3
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.test.js +84 -1
- package/test/logger.test.js +98 -58
- package/test/maxRequestsPerSocket.test.js +8 -6
- package/test/middleware.test.js +2 -25
- package/test/noop-set.test.js +19 -0
- package/test/nullable-validation.test.js +51 -14
- package/test/plugin.test.js +31 -5
- package/test/pretty-print.test.js +22 -10
- package/test/reply-error.test.js +123 -12
- package/test/request-error.test.js +2 -5
- package/test/route-hooks.test.js +17 -17
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +216 -20
- package/test/router-options.test.js +1 -1
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +24 -19
- package/test/schema-serialization.test.js +50 -9
- package/test/schema-special-usage.test.js +14 -81
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +8 -8
- package/test/stream.test.js +23 -12
- package/test/throw.test.js +8 -5
- package/test/trust-proxy.test.js +1 -1
- package/test/type-provider.test.js +20 -0
- package/test/types/fastify.test-d.ts +12 -18
- package/test/types/hooks.test-d.ts +7 -3
- package/test/types/import.js +2 -0
- package/test/types/import.ts +1 -0
- package/test/types/instance.test-d.ts +61 -15
- package/test/types/logger.test-d.ts +44 -15
- package/test/types/route.test-d.ts +8 -2
- package/test/types/schema.test-d.ts +2 -39
- package/test/types/type-provider.test-d.ts +417 -0
- package/test/validation-error-handling.test.js +9 -9
- package/test/versioned-routes.test.js +29 -17
- package/test/wrapThenable.test.js +7 -6
- package/types/.eslintrc.json +1 -1
- package/types/content-type-parser.d.ts +17 -8
- package/types/hooks.d.ts +107 -60
- package/types/instance.d.ts +137 -105
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/register.d.ts +1 -1
- package/types/reply.d.ts +16 -11
- package/types/request.d.ts +10 -5
- package/types/route.d.ts +42 -31
- package/types/schema.d.ts +15 -1
- package/types/type-provider.d.ts +99 -0
- package/types/utils.d.ts +1 -1
- package/lib/schema-compilers.js +0 -12
- package/test/emit-warning.test.js +0 -166
package/docs/Reference/Server.md
CHANGED
|
@@ -13,6 +13,7 @@ describes the properties available in that options object.
|
|
|
13
13
|
- [`https`](#https)
|
|
14
14
|
- [`connectionTimeout`](#connectiontimeout)
|
|
15
15
|
- [`keepAliveTimeout`](#keepalivetimeout)
|
|
16
|
+
- [`forceCloseConnections`](#forcecloseconnections)
|
|
16
17
|
- [`maxRequestsPerSocket`](#maxrequestspersocket)
|
|
17
18
|
- [`requestTimeout`](#requesttimeout)
|
|
18
19
|
- [`ignoreTrailingSlash`](#ignoretrailingslash)
|
|
@@ -46,6 +47,7 @@ describes the properties available in that options object.
|
|
|
46
47
|
- [after](#after)
|
|
47
48
|
- [ready](#ready)
|
|
48
49
|
- [listen](#listen)
|
|
50
|
+
- [addresses](#addresses)
|
|
49
51
|
- [getDefaultRoute](#getdefaultroute)
|
|
50
52
|
- [setDefaultRoute](#setdefaultroute)
|
|
51
53
|
- [routing](#routing)
|
|
@@ -76,6 +78,9 @@ describes the properties available in that options object.
|
|
|
76
78
|
- [printRoutes](#printroutes)
|
|
77
79
|
- [printPlugins](#printplugins)
|
|
78
80
|
- [addContentTypeParser](#addcontenttypeparser)
|
|
81
|
+
- [hasContentTypeParser](#hasContentTypeParser)
|
|
82
|
+
- [removeContentTypeParser](#removeContentTypeParser)
|
|
83
|
+
- [removeAllContentTypeParsers](#removeAllContentTypeParsers)
|
|
79
84
|
- [getDefaultJsonParser](#getdefaultjsonparser)
|
|
80
85
|
- [defaultTextParser](#defaulttextparser)
|
|
81
86
|
- [errorHandler](#errorhandler)
|
|
@@ -122,7 +127,20 @@ property](https://nodejs.org/api/http.html#http_server_keepalivetimeout) to
|
|
|
122
127
|
understand the effect of this option. This option only applies when HTTP/1 is in
|
|
123
128
|
use. Also, when `serverFactory` option is specified, this option is ignored.
|
|
124
129
|
|
|
125
|
-
+ Default: `
|
|
130
|
+
+ Default: `72000` (72 seconds)
|
|
131
|
+
|
|
132
|
+
### `forceCloseConnections`
|
|
133
|
+
<a id="forcecloseconnections"></a>
|
|
134
|
+
|
|
135
|
+
When set to `true` requests with the header `connection: keep-alive` will be
|
|
136
|
+
tracked by the server. Upon [`close`](#close), the server will iterate the
|
|
137
|
+
current persistent connections and [destroy their
|
|
138
|
+
sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror).
|
|
139
|
+
This means the server will shutdown immediately instead of waiting for existing
|
|
140
|
+
persistent connections to timeout first. Important: connections are not
|
|
141
|
+
inspected to determine if requests have been completed.
|
|
142
|
+
|
|
143
|
+
+ Default: `false`
|
|
126
144
|
|
|
127
145
|
### `maxRequestsPerSocket`
|
|
128
146
|
<a id="factory-max-requests-per-socket"></a>
|
|
@@ -536,7 +554,7 @@ Automatically creates a sibling `HEAD` route for each `GET` route defined. If
|
|
|
536
554
|
you want a custom `HEAD` handler without disabling this option, make sure to
|
|
537
555
|
define it before the `GET` route.
|
|
538
556
|
|
|
539
|
-
+ Default: `
|
|
557
|
+
+ Default: `true`
|
|
540
558
|
|
|
541
559
|
### `constraints`
|
|
542
560
|
<a id="constraints"></a>
|
|
@@ -582,28 +600,14 @@ the incoming request as usual.
|
|
|
582
600
|
### `ajv`
|
|
583
601
|
<a id="factory-ajv"></a>
|
|
584
602
|
|
|
585
|
-
Configure the Ajv
|
|
586
|
-
|
|
587
|
-
+ Default:
|
|
588
|
-
|
|
589
|
-
```js
|
|
590
|
-
{
|
|
591
|
-
customOptions: {
|
|
592
|
-
removeAdditional: true,
|
|
593
|
-
useDefaults: true,
|
|
594
|
-
coerceTypes: true,
|
|
595
|
-
allErrors: false,
|
|
596
|
-
nullable: true
|
|
597
|
-
},
|
|
598
|
-
plugins: []
|
|
599
|
-
}
|
|
600
|
-
```
|
|
603
|
+
Configure the Ajv v8 instance used by Fastify without providing a custom one.
|
|
604
|
+
The default configuration is explained in the [#schema-validator](Validation-and-Serialization.md#schema-validator) section.
|
|
601
605
|
|
|
602
606
|
```js
|
|
603
607
|
const fastify = require('fastify')({
|
|
604
608
|
ajv: {
|
|
605
609
|
customOptions: {
|
|
606
|
-
|
|
610
|
+
removeAdditional: 'all' // Refer to [ajv options](https://ajv.js.org/#options)
|
|
607
611
|
},
|
|
608
612
|
plugins: [
|
|
609
613
|
require('ajv-merge-patch'),
|
|
@@ -636,7 +640,7 @@ const fastify = require('fastify')({
|
|
|
636
640
|
Set a default
|
|
637
641
|
[timeout](https://nodejs.org/api/http2.html#http2_http2session_settimeout_msecs_callback)
|
|
638
642
|
to every incoming HTTP/2 session. The session will be closed on the timeout.
|
|
639
|
-
Default: `
|
|
643
|
+
Default: `72000` ms.
|
|
640
644
|
|
|
641
645
|
Note that this is needed to offer the graceful "close" experience when using
|
|
642
646
|
HTTP/2. The low default has been chosen to mitigate denial of service attacks.
|
|
@@ -817,14 +821,25 @@ fastify.ready().then(() => {
|
|
|
817
821
|
<a id="listen"></a>
|
|
818
822
|
|
|
819
823
|
Starts the server on the given port after all the plugins are loaded, internally
|
|
820
|
-
waits for the `.ready()` event. The callback is the same as the Node core.
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
`0.0.0.0` for the address will listen on all IPv4 addresses.
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
824
|
+
waits for the `.ready()` event. The callback is the same as the Node core.
|
|
825
|
+
|
|
826
|
+
By default, the server will listen on the address(es) resolved by `localhost` when no
|
|
827
|
+
specific address is provided. If listening on any available interface is desired,
|
|
828
|
+
then specifying `0.0.0.0` for the address will listen on all IPv4 addresses.
|
|
829
|
+
|
|
830
|
+
Host | IPv4 | IPv6
|
|
831
|
+
--------------|------|-------
|
|
832
|
+
`::` | ✅<sup>*</sup> | ✅
|
|
833
|
+
`::` + [`ipv6Only`](https://nodejs.org/api/net.html#serverlistenoptions-callback) | 🚫 | ✅
|
|
834
|
+
`0.0.0.0` | ✅ | 🚫
|
|
835
|
+
`localhost` | ✅ | ✅
|
|
836
|
+
`127.0.0.1` | ✅ | 🚫
|
|
837
|
+
`::1` | 🚫 | ✅
|
|
838
|
+
|
|
839
|
+
<sup>*</sup> Using `::` for the address will listen on all IPv6 addresses and, depending on OS,
|
|
840
|
+
may also listen on [all IPv4 addresses](https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback).
|
|
841
|
+
|
|
842
|
+
Be careful when deciding to listen on all interfaces; it comes with inherent [security
|
|
828
843
|
risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
|
|
829
844
|
|
|
830
845
|
```js
|
|
@@ -933,6 +948,24 @@ fastify.listen({
|
|
|
933
948
|
}, (err) => {})
|
|
934
949
|
```
|
|
935
950
|
|
|
951
|
+
#### addresses
|
|
952
|
+
<a id="addresses"></a>
|
|
953
|
+
|
|
954
|
+
This method returns an array of addresses that the server is listening on.
|
|
955
|
+
If you call it before `listen()` is called or after the `close()` function,
|
|
956
|
+
it will return an empty array.
|
|
957
|
+
|
|
958
|
+
```js
|
|
959
|
+
await fastify.listen(8080)
|
|
960
|
+
const addresses = fastify.addresses()
|
|
961
|
+
// [
|
|
962
|
+
// { port: 8080, family: 'IPv6', address: '::1' },
|
|
963
|
+
// { port: 8080, family: 'IPv4', address: '127.0.0.1' }
|
|
964
|
+
// ]
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
Note that the array contains the `fastify.server.address()` too.
|
|
968
|
+
|
|
936
969
|
#### getDefaultRoute
|
|
937
970
|
<a id="getDefaultRoute"></a>
|
|
938
971
|
|
|
@@ -1171,8 +1204,10 @@ unknown to Fastify. See [issue
|
|
|
1171
1204
|
#2446](https://github.com/fastify/fastify/issues/2446) for an example of what
|
|
1172
1205
|
this property helps to resolve.
|
|
1173
1206
|
|
|
1174
|
-
Another use case is to tweak all the schemas processing.
|
|
1175
|
-
|
|
1207
|
+
Another use case is to tweak all the schemas processing.
|
|
1208
|
+
Doing so it is possible to use Ajv v8 JTD or Standalone feature. To use such
|
|
1209
|
+
as JTD or the Standalone mode, refers to the
|
|
1210
|
+
[`@fastify/ajv-compiler` documentation](https://github.com/fastify/ajv-compiler#usage).
|
|
1176
1211
|
|
|
1177
1212
|
```js
|
|
1178
1213
|
const fastify = Fastify({
|
|
@@ -1247,39 +1282,6 @@ const fastify = Fastify({
|
|
|
1247
1282
|
});
|
|
1248
1283
|
```
|
|
1249
1284
|
|
|
1250
|
-
##### Ajv 8 as default schema validator
|
|
1251
|
-
|
|
1252
|
-
Ajv 8 is the evolution of Ajv 6, and it has a lot of improvements and new
|
|
1253
|
-
features. To use the new Ajv 8 features such as JTD or the Standalone mode,
|
|
1254
|
-
refer to the [`@fastify/ajv-compiler`
|
|
1255
|
-
documentation](https://github.com/fastify/ajv-compiler#usage).
|
|
1256
|
-
|
|
1257
|
-
To use Ajv 8 as default schema validator, you can use the following code:
|
|
1258
|
-
|
|
1259
|
-
```js
|
|
1260
|
-
const AjvCompiler = require('@fastify/ajv-compiler') // It must be the v2.x.x version
|
|
1261
|
-
|
|
1262
|
-
// Note that the `format` schema's keyword is no longer supported on Ajv 8 by default.
|
|
1263
|
-
// So you need to add it manually.
|
|
1264
|
-
const ajvFormats = require('ajv-formats')
|
|
1265
|
-
|
|
1266
|
-
const app = fastify({
|
|
1267
|
-
ajv: {
|
|
1268
|
-
customOptions: {
|
|
1269
|
-
validateFormats: true
|
|
1270
|
-
},
|
|
1271
|
-
plugins: [ajvFormats]
|
|
1272
|
-
},
|
|
1273
|
-
schemaController: {
|
|
1274
|
-
compilersFactory: {
|
|
1275
|
-
buildValidator: AjvCompiler()
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
})
|
|
1279
|
-
|
|
1280
|
-
// Done! You can now use Ajv 8 options and keywords in your schemas!
|
|
1281
|
-
```
|
|
1282
|
-
|
|
1283
1285
|
#### setNotFoundHandler
|
|
1284
1286
|
<a id="set-not-found-handler"></a>
|
|
1285
1287
|
|
|
@@ -1465,6 +1467,39 @@ content types, e.g. `text/json, application/vnd.oasis.opendocument.text`.
|
|
|
1465
1467
|
fastify.addContentTypeParser('text/json', { asString: true }, fastify.getDefaultJsonParser('ignore', 'ignore'))
|
|
1466
1468
|
```
|
|
1467
1469
|
|
|
1470
|
+
#### hasContentTypeParser
|
|
1471
|
+
<a id="hasContentTypeParser"></a>
|
|
1472
|
+
|
|
1473
|
+
`fastify.hasContentTypeParser(contentType)` is used to check whether there is a content type parser in the current
|
|
1474
|
+
context for the specified content type.
|
|
1475
|
+
|
|
1476
|
+
```js
|
|
1477
|
+
fastify.hasContentTypeParser('text/json')
|
|
1478
|
+
|
|
1479
|
+
fastify.hasContentTypeParser(/^.+\/json$/)
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1482
|
+
#### removeContentTypeParser
|
|
1483
|
+
<a id="removeContentTypeParser"></a>
|
|
1484
|
+
|
|
1485
|
+
`fastify.removeContentTypeParser(contentType)` is used to remove content type parsers in the current context. This
|
|
1486
|
+
method allows for example to remove the both built-in parsers for `application/json` and `text/plain`.
|
|
1487
|
+
|
|
1488
|
+
```js
|
|
1489
|
+
fastify.removeContentTypeParser('application/json')
|
|
1490
|
+
|
|
1491
|
+
fastify.removeContentTypeParser(['application/json', 'text/plain'])
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
#### removeAllContentTypeParsers
|
|
1495
|
+
<a id="removeAllContentTypeParsers"></a>
|
|
1496
|
+
|
|
1497
|
+
The `fastify.removeAllContentTypeParsers()` method allows all content type parsers in the current context to be removed.
|
|
1498
|
+
A use case of this method is the implementation of catch-all content type parser. Before adding this parser with
|
|
1499
|
+
`fastify.addContentTypeParser()` one could call the `removeAllContentTypeParsers` method.
|
|
1500
|
+
|
|
1501
|
+
For more details about the usage of the different content type parser APIs see [here](./ContentTypeParser.md#usage).
|
|
1502
|
+
|
|
1468
1503
|
#### getDefaultJsonParser
|
|
1469
1504
|
<a id="getDefaultJsonParser"></a>
|
|
1470
1505
|
|
|
@@ -399,7 +399,7 @@ const todo = {
|
|
|
399
399
|
done: { type: 'boolean' },
|
|
400
400
|
},
|
|
401
401
|
required: ['name'],
|
|
402
|
-
} as const;
|
|
402
|
+
} as const; // don't forget to use const !
|
|
403
403
|
```
|
|
404
404
|
|
|
405
405
|
With the provided type `FromSchema` you can build a type from your schema and
|
|
@@ -487,6 +487,7 @@ Fastify Plugin in a TypeScript Project.
|
|
|
487
487
|
import fp from 'fastify-plugin'
|
|
488
488
|
|
|
489
489
|
// using declaration merging, add your plugin props to the appropriate fastify interfaces
|
|
490
|
+
// if prop type is defined here, the value will be typechecked when you call decorate{,Request,Reply}
|
|
490
491
|
declare module 'fastify' {
|
|
491
492
|
interface FastifyRequest {
|
|
492
493
|
myPluginProp: string
|
|
@@ -877,26 +878,23 @@ server.get('/', async (request, reply) => {
|
|
|
877
878
|
|
|
878
879
|
###### Example 5: Specifying logger types
|
|
879
880
|
|
|
880
|
-
Fastify uses [Pino](https://getpino.io/#/) logging library under the hood.
|
|
881
|
-
of it's properties can be configured via `logger` field when
|
|
882
|
-
Fastify's instance. If properties you need aren't exposed,
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
To use an external instance of Pino, add `@types/pino` to devDependencies and
|
|
888
|
-
pass the instance to `logger` field:
|
|
881
|
+
Fastify uses [Pino](https://getpino.io/#/) logging library under the hood. Since
|
|
882
|
+
`pino@7`, all of it's properties can be configured via `logger` field when
|
|
883
|
+
constructing Fastify's instance. If properties you need aren't exposed, please
|
|
884
|
+
open an Issue to [`Pino`](https://github.com/pinojs/pino/issues) or pass a
|
|
885
|
+
preconfigured external instance of Pino (or any other compatible logger) as
|
|
886
|
+
temporary fix to Fastify via the same field. This allows creating custom
|
|
887
|
+
serializers as well, see the [Logging](Logging.md) documentation for more info.
|
|
889
888
|
|
|
890
889
|
```typescript
|
|
891
890
|
import fastify from 'fastify'
|
|
892
|
-
import pino from 'pino'
|
|
893
891
|
|
|
894
892
|
const server = fastify({
|
|
895
|
-
logger:
|
|
893
|
+
logger: {
|
|
896
894
|
level: 'info',
|
|
897
895
|
redact: ['x-userinfo'],
|
|
898
896
|
messageKey: 'message'
|
|
899
|
-
}
|
|
897
|
+
}
|
|
900
898
|
})
|
|
901
899
|
|
|
902
900
|
server.get('/', async (request, reply) => {
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
Fastify uses a schema-based approach, and even if it is not mandatory we
|
|
5
5
|
recommend using [JSON Schema](https://json-schema.org/) to validate your routes
|
|
6
6
|
and serialize your outputs. Internally, Fastify compiles the schema into a
|
|
7
|
-
highly performant function.
|
|
7
|
+
highly performant function.
|
|
8
|
+
|
|
9
|
+
Validation will only be attempted if the content type is `application-json`,
|
|
10
|
+
as described in the documentation for the [content type parser](./ContentTypeParser.md).
|
|
11
|
+
|
|
12
|
+
All the examples in this section are using the [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7) specification.
|
|
8
13
|
|
|
9
14
|
> ## ⚠ Security Notice
|
|
10
15
|
> Treat the schema definition as application code. Validation and serialization
|
|
@@ -23,8 +28,7 @@ highly performant function.
|
|
|
23
28
|
### Core concepts
|
|
24
29
|
The validation and the serialization tasks are processed by two different, and
|
|
25
30
|
customizable, actors:
|
|
26
|
-
- [Ajv
|
|
27
|
-
request
|
|
31
|
+
- [Ajv v8](https://www.npmjs.com/package/ajv) for the validation of a request
|
|
28
32
|
- [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) for
|
|
29
33
|
the serialization of a response's body
|
|
30
34
|
|
|
@@ -143,10 +147,11 @@ fastify.register((instance, opts, done) => {
|
|
|
143
147
|
|
|
144
148
|
|
|
145
149
|
### Validation
|
|
146
|
-
The route validation internally relies upon
|
|
147
|
-
|
|
148
|
-
Schema validator.
|
|
149
|
-
|
|
150
|
+
The route validation internally relies upon
|
|
151
|
+
[Ajv v8](https://www.npmjs.com/package/ajv) which is a high-performance
|
|
152
|
+
JSON Schema validator.
|
|
153
|
+
Validating the input is very easy: just add the fields that you need
|
|
154
|
+
inside the route schema, and you are done!
|
|
150
155
|
|
|
151
156
|
The supported validations are:
|
|
152
157
|
- `body`: validates the body of the request if it is a POST, PUT, or PATCH
|
|
@@ -229,15 +234,13 @@ const schema = {
|
|
|
229
234
|
fastify.post('/the/url', { schema }, handler)
|
|
230
235
|
```
|
|
231
236
|
|
|
232
|
-
*Note that Ajv will try to
|
|
233
|
-
[coerce](https://github.com/epoberezkin/ajv#coercing-data-types) the values to
|
|
237
|
+
*Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html) the values to
|
|
234
238
|
the types specified in your schema `type` keywords, both to pass the validation
|
|
235
239
|
and to use the correctly typed data afterwards.*
|
|
236
240
|
|
|
237
|
-
The Ajv default configuration in Fastify
|
|
238
|
-
parameters in querystring
|
|
239
|
-
|
|
240
|
-
will coerce one parameter to a single element in array. Example:
|
|
241
|
+
The Ajv default configuration in Fastify supports coercing array
|
|
242
|
+
parameters in `querystring`.
|
|
243
|
+
Example:
|
|
241
244
|
|
|
242
245
|
```js
|
|
243
246
|
const opts = {
|
|
@@ -255,7 +258,7 @@ const opts = {
|
|
|
255
258
|
}
|
|
256
259
|
|
|
257
260
|
fastify.get('/', opts, (request, reply) => {
|
|
258
|
-
reply.send({ params: request.query })
|
|
261
|
+
reply.send({ params: request.query }) // echo the querystring
|
|
259
262
|
})
|
|
260
263
|
|
|
261
264
|
fastify.listen(3000, (err) => {
|
|
@@ -263,29 +266,6 @@ fastify.listen(3000, (err) => {
|
|
|
263
266
|
})
|
|
264
267
|
```
|
|
265
268
|
|
|
266
|
-
Using Fastify defaults the following request will result in `400` status code:
|
|
267
|
-
|
|
268
|
-
```sh
|
|
269
|
-
curl -X GET "http://localhost:3000/?ids=1
|
|
270
|
-
|
|
271
|
-
{"statusCode":400,"error":"Bad Request","message":"querystring/hello should be array"}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Using `coerceTypes` as 'array' will fix it:
|
|
275
|
-
|
|
276
|
-
```js
|
|
277
|
-
const ajv = new Ajv({
|
|
278
|
-
removeAdditional: true,
|
|
279
|
-
useDefaults: true,
|
|
280
|
-
coerceTypes: 'array', // This line
|
|
281
|
-
allErrors: true
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
|
285
|
-
return ajv.compile(schema)
|
|
286
|
-
})
|
|
287
|
-
```
|
|
288
|
-
|
|
289
269
|
```sh
|
|
290
270
|
curl -X GET "http://localhost:3000/?ids=1
|
|
291
271
|
|
|
@@ -339,8 +319,8 @@ For further information see [here](https://ajv.js.org/coercion.html)
|
|
|
339
319
|
#### Ajv Plugins
|
|
340
320
|
<a id="ajv-plugins"></a>
|
|
341
321
|
|
|
342
|
-
You can provide a list of plugins you want to use with the default `ajv`
|
|
343
|
-
|
|
322
|
+
You can provide a list of plugins you want to use with the default `ajv` instance.
|
|
323
|
+
Note that the plugin must be **compatible with the Ajv version shipped within Fastify**.
|
|
344
324
|
|
|
345
325
|
> Refer to [`ajv options`](./Server.md#ajv) to check plugins format
|
|
346
326
|
|
|
@@ -409,16 +389,16 @@ body, URL parameters, headers, and query string. The default
|
|
|
409
389
|
[ajv](https://ajv.js.org/) validation interface. Fastify uses it internally to
|
|
410
390
|
speed the validation up.
|
|
411
391
|
|
|
412
|
-
Fastify's [baseline ajv
|
|
413
|
-
configuration](https://github.com/epoberezkin/ajv#options-to-modify-validated-data)
|
|
414
|
-
is:
|
|
392
|
+
Fastify's [baseline ajv configuration](https://github.com/fastify/ajv-compiler#ajv-configuration) is:
|
|
415
393
|
|
|
416
394
|
```js
|
|
417
395
|
{
|
|
418
|
-
removeAdditional: true, // remove additional properties
|
|
419
|
-
useDefaults: true, // replace missing properties and items with the values from corresponding default keyword
|
|
420
396
|
coerceTypes: true, // change data type of data to match type keyword
|
|
421
|
-
|
|
397
|
+
useDefaults: true, // replace missing properties and items with the values from corresponding default keyword
|
|
398
|
+
removeAdditional: true, // remove additional properties
|
|
399
|
+
// Explicitly set allErrors to `false`.
|
|
400
|
+
// When set to `true`, a DoS attack is possible.
|
|
401
|
+
allErrors: false
|
|
422
402
|
}
|
|
423
403
|
```
|
|
424
404
|
|
|
@@ -432,11 +412,9 @@ your own instance and override the existing one like:
|
|
|
432
412
|
const fastify = require('fastify')()
|
|
433
413
|
const Ajv = require('ajv')
|
|
434
414
|
const ajv = new Ajv({
|
|
435
|
-
|
|
436
|
-
removeAdditional: true,
|
|
415
|
+
removeAdditional: 'all',
|
|
437
416
|
useDefaults: true,
|
|
438
|
-
coerceTypes:
|
|
439
|
-
nullable: true,
|
|
417
|
+
coerceTypes: 'array',
|
|
440
418
|
// any other options
|
|
441
419
|
// ...
|
|
442
420
|
})
|
|
@@ -457,7 +435,7 @@ almost any Javascript validation library ([joi](https://github.com/hapijs/joi/),
|
|
|
457
435
|
[yup](https://github.com/jquense/yup/), ...) or a custom one:
|
|
458
436
|
|
|
459
437
|
```js
|
|
460
|
-
const Joi = require('
|
|
438
|
+
const Joi = require('joi')
|
|
461
439
|
|
|
462
440
|
fastify.post('/the/url', {
|
|
463
441
|
schema: {
|
|
@@ -509,8 +487,8 @@ fastify.post('/the/url', {
|
|
|
509
487
|
|
|
510
488
|
Fastify's validation error messages are tightly coupled to the default
|
|
511
489
|
validation engine: errors returned from `ajv` are eventually run through the
|
|
512
|
-
`
|
|
513
|
-
error messages. However, the `
|
|
490
|
+
`schemaErrorFormatter` function which is responsible for building human-friendly
|
|
491
|
+
error messages. However, the `schemaErrorFormatter` function is written with `ajv`
|
|
514
492
|
in mind : as a result, you may run into odd or incomplete error messages when
|
|
515
493
|
using other validation libraries.
|
|
516
494
|
|
|
@@ -526,9 +504,9 @@ To circumvent this issue, you have 2 main options :
|
|
|
526
504
|
To help you in writing a custom `errorHandler`, Fastify adds 2 properties to all
|
|
527
505
|
validation errors:
|
|
528
506
|
|
|
529
|
-
* validation
|
|
507
|
+
* `validation`: the content of the `error` property of the object returned by the
|
|
530
508
|
validation function (returned by your custom `schemaCompiler`)
|
|
531
|
-
* validationContext
|
|
509
|
+
* `validationContext`: the 'context' (body, params, query, headers) where the
|
|
532
510
|
validation error occurred
|
|
533
511
|
|
|
534
512
|
A very contrived example of such a custom `errorHandler` handling validation
|