fastify 4.0.0-rc.2 → 4.0.0-rc.3
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 +2 -3
- package/docs/Guides/Ecosystem.md +3 -3
- package/docs/Guides/Getting-Started.md +49 -3
- package/docs/Guides/Write-Plugin.md +3 -3
- package/docs/Migration-Guide-V4.md +1 -1
- package/docs/Reference/Errors.md +0 -7
- package/docs/Reference/Plugins.md +1 -1
- package/docs/Reference/Routes.md +21 -0
- package/docs/Reference/Server.md +46 -6
- package/docs/{Type-Providers.md → Reference/Type-Providers.md} +0 -0
- package/docs/Reference/TypeScript.md +11 -1
- package/fastify.js +12 -10
- package/lib/hooks.js +4 -0
- package/lib/pluginUtils.js +2 -2
- package/lib/route.js +33 -7
- package/lib/server.js +52 -1
- package/package.json +2 -2
- package/test/constrained-routes.test.js +262 -4
- package/test/hooks.test.js +58 -0
- package/test/internals/initialConfig.test.js +4 -8
- package/test/internals/server.test.js +5 -5
- package/test/listen.test.js +9 -3
- package/test/types/instance.test-d.ts +17 -0
- package/test/unsupported-httpversion.test.js +57 -0
- package/test/versioned-routes.test.js +4 -8
- package/types/instance.d.ts +7 -1
package/README.md
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
[](https://github.com/fastify/fastify/actions/workflows/ci.yml)
|
|
9
9
|
[](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
|
10
10
|
[](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
|
11
|
-
[](https://snyk.io/test/github/fastify/fastify)
|
|
12
11
|
[](https://standardjs.com/)
|
|
13
12
|
|
|
14
13
|
</div>
|
|
@@ -18,7 +17,7 @@
|
|
|
18
17
|
[](https://www.npmjs.com/package/fastify)
|
|
19
18
|
[](https://www.npmjs.com/package/fastify)
|
|
20
19
|
[](https://github.com/
|
|
20
|
+
Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/fastify/fastify/blob/main/SECURITY.md)
|
|
22
21
|
[](https://discord.gg/fastify)
|
|
23
22
|
|
|
24
23
|
</div>
|
|
@@ -282,7 +281,7 @@ Great contributors on a specific area in the Fastify ecosystem will be invited t
|
|
|
282
281
|
|
|
283
282
|
## Hosted by
|
|
284
283
|
|
|
285
|
-
[<img src="https://github.com/openjs-foundation/
|
|
284
|
+
[<img src="https://github.com/openjs-foundation/artwork/blob/main/openjs_foundation/openjs_foundation-logo-horizontal-color.png?raw=true" width="250px;"/>](https://openjsf.org/projects/#growth)
|
|
286
285
|
|
|
287
286
|
We are a [Growth Project](https://github.com/openjs-foundation/cross-project-council/blob/HEAD/PROJECT_PROGRESSION.md#growth-stage) in the [OpenJS Foundation](https://openjsf.org/).
|
|
288
287
|
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -22,8 +22,6 @@ section.
|
|
|
22
22
|
- [`fastify-awilix`](https://github.com/fastify/fastify-awilix) Dependency
|
|
23
23
|
injection support for Fastify, based on
|
|
24
24
|
[awilix](https://github.com/jeffijoe/awilix).
|
|
25
|
-
- [`@fastify/bankai`](https://github.com/fastify/fastify-bankai)
|
|
26
|
-
[Bankai](https://github.com/yoshuawuyts/bankai) assets compiler for Fastify.
|
|
27
25
|
- [`@fastify/basic-auth`](https://github.com/fastify/fastify-basic-auth) Basic
|
|
28
26
|
auth plugin for Fastify.
|
|
29
27
|
- [`@fastify/bearer-auth`](https://github.com/fastify/fastify-bearer-auth) Bearer
|
|
@@ -38,7 +36,7 @@ section.
|
|
|
38
36
|
cookie headers.
|
|
39
37
|
- [`@fastify/cors`](https://github.com/fastify/fastify-cors) Enables the use of
|
|
40
38
|
CORS in a Fastify application.
|
|
41
|
-
- [
|
|
39
|
+
- [`@fastify/csrf-protection`](https://github.com/fastify/csrf-protection) A plugin for adding
|
|
42
40
|
[CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection to
|
|
43
41
|
Fastify.
|
|
44
42
|
- [`@fastify/diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel)
|
|
@@ -59,6 +57,7 @@ section.
|
|
|
59
57
|
function.
|
|
60
58
|
- [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important
|
|
61
59
|
security headers for Fastify.
|
|
60
|
+
- [`@fastify/hotwire`](https://github.com/fastify/fastify-hotwire) Use the Hotwire pattern with Fastify.
|
|
62
61
|
- [`@fastify/http-proxy`](https://github.com/fastify/fastify-http-proxy) Proxy
|
|
63
62
|
your HTTP requests to another server, with hooks.
|
|
64
63
|
- [`@fastify/jwt`](https://github.com/fastify/fastify-jwt) JWT utils for Fastify,
|
|
@@ -405,6 +404,7 @@ section.
|
|
|
405
404
|
- [`fastify-qs`](https://github.com/webdevium/fastify-qs) A plugin for Fastify
|
|
406
405
|
that adds support for parsing URL query parameters with
|
|
407
406
|
[qs](https://github.com/ljharb/qs).
|
|
407
|
+
- [`fastify-racing`](https://github.com/metcoder95/fastify-racing) Fastify's plugin that adds support to handle an aborted request asynchronous.
|
|
408
408
|
- [`fastify-raw-body`](https://github.com/Eomm/fastify-raw-body) Add the
|
|
409
409
|
`request.rawBody` field.
|
|
410
410
|
- [`fastify-rbac`](https://gitlab.com/m03geek/fastify-rbac) Fastify role-based
|
|
@@ -56,9 +56,6 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
|
|
56
56
|
|
|
57
57
|
Do you prefer to use `async/await`? Fastify supports it out-of-the-box.
|
|
58
58
|
|
|
59
|
-
*(We also suggest using
|
|
60
|
-
[make-promises-safe](https://github.com/mcollina/make-promises-safe) to avoid
|
|
61
|
-
file descriptor and memory leaks.)*
|
|
62
59
|
```js
|
|
63
60
|
// ESM
|
|
64
61
|
import Fastify from 'fastify'
|
|
@@ -74,6 +71,9 @@ fastify.get('/', async (request, reply) => {
|
|
|
74
71
|
return { hello: 'world' }
|
|
75
72
|
})
|
|
76
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Run the server!
|
|
76
|
+
*/
|
|
77
77
|
const start = async () => {
|
|
78
78
|
try {
|
|
79
79
|
await fastify.listen({ port: 3000 })
|
|
@@ -133,6 +133,9 @@ declaration](../Reference/Routes.md) docs).
|
|
|
133
133
|
// ESM
|
|
134
134
|
import Fastify from 'fastify'
|
|
135
135
|
import firstRoute from './our-first-route'
|
|
136
|
+
/**
|
|
137
|
+
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
138
|
+
*/
|
|
136
139
|
const fastify = Fastify({
|
|
137
140
|
logger: true
|
|
138
141
|
})
|
|
@@ -150,6 +153,9 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
|
|
150
153
|
|
|
151
154
|
```js
|
|
152
155
|
// CommonJs
|
|
156
|
+
/**
|
|
157
|
+
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
158
|
+
*/
|
|
153
159
|
const fastify = require('fastify')({
|
|
154
160
|
logger: true
|
|
155
161
|
})
|
|
@@ -168,6 +174,11 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
|
|
168
174
|
```js
|
|
169
175
|
// our-first-route.js
|
|
170
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Encapsulates the routes
|
|
179
|
+
* @param {FastifyInstance} fastify Encapsulated Fastify Instance
|
|
180
|
+
* @param {Object} options plugin options, refer to https://www.fastify.io/docs/latest/Reference/Plugins/#plugin-options
|
|
181
|
+
*/
|
|
171
182
|
async function routes (fastify, options) {
|
|
172
183
|
fastify.get('/', async (request, reply) => {
|
|
173
184
|
return { hello: 'world' }
|
|
@@ -208,6 +219,9 @@ import Fastify from 'fastify'
|
|
|
208
219
|
import dbConnector from './our-db-connector'
|
|
209
220
|
import firstRoute from './our-first-route'
|
|
210
221
|
|
|
222
|
+
/**
|
|
223
|
+
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
224
|
+
*/
|
|
211
225
|
const fastify = Fastify({
|
|
212
226
|
logger: true
|
|
213
227
|
})
|
|
@@ -225,6 +239,9 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
|
|
225
239
|
|
|
226
240
|
```js
|
|
227
241
|
// CommonJs
|
|
242
|
+
/**
|
|
243
|
+
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
|
244
|
+
*/
|
|
228
245
|
const fastify = require('fastify')({
|
|
229
246
|
logger: true
|
|
230
247
|
})
|
|
@@ -248,6 +265,10 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
|
|
248
265
|
import fastifyPlugin from 'fastify-plugin'
|
|
249
266
|
import fastifyMongo from '@fastify/mongodb'
|
|
250
267
|
|
|
268
|
+
/**
|
|
269
|
+
* @param {FastifyInstance} fastify
|
|
270
|
+
* @param {Object} options
|
|
271
|
+
*/
|
|
251
272
|
async function dbConnector (fastify, options) {
|
|
252
273
|
fastify.register(fastifyMongo, {
|
|
253
274
|
url: 'mongodb://localhost:27017/test_database'
|
|
@@ -262,8 +283,17 @@ module.exports = fastifyPlugin(dbConnector)
|
|
|
262
283
|
|
|
263
284
|
```js
|
|
264
285
|
// CommonJs
|
|
286
|
+
/**
|
|
287
|
+
* @type {import('fastify-plugin').FastifyPlugin}
|
|
288
|
+
*/
|
|
265
289
|
const fastifyPlugin = require('fastify-plugin')
|
|
266
290
|
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Connects to a MongoDB database
|
|
294
|
+
* @param {FastifyInstance} fastify Encapsulated Fastify Instance
|
|
295
|
+
* @param {Object} options plugin options, refer to https://www.fastify.io/docs/latest/Reference/Plugins/#plugin-options
|
|
296
|
+
*/
|
|
267
297
|
async function dbConnector (fastify, options) {
|
|
268
298
|
fastify.register(require('@fastify/mongodb'), {
|
|
269
299
|
url: 'mongodb://localhost:27017/test_database'
|
|
@@ -278,6 +308,11 @@ module.exports = fastifyPlugin(dbConnector)
|
|
|
278
308
|
|
|
279
309
|
**our-first-route.js**
|
|
280
310
|
```js
|
|
311
|
+
/**
|
|
312
|
+
* A plugin that provide encapsulated routes
|
|
313
|
+
* @param {FastifyInstance} fastify encapsulated fastify instance
|
|
314
|
+
* @param {Object} options plugin options, refer to https://www.fastify.io/docs/latest/Reference/Plugins/#plugin-options
|
|
315
|
+
*/
|
|
281
316
|
async function routes (fastify, options) {
|
|
282
317
|
const collection = fastify.mongo.db.collection('test_collection')
|
|
283
318
|
|
|
@@ -403,6 +438,10 @@ Schema](https://json-schema.org/).
|
|
|
403
438
|
|
|
404
439
|
Let's look at an example demonstrating validation for routes:
|
|
405
440
|
```js
|
|
441
|
+
/**
|
|
442
|
+
* @type {import('fastify').RouteShorthandOptions}
|
|
443
|
+
* @const
|
|
444
|
+
*/
|
|
406
445
|
const opts = {
|
|
407
446
|
schema: {
|
|
408
447
|
body: {
|
|
@@ -435,6 +474,10 @@ JSON bodies and serialize JSON output.
|
|
|
435
474
|
To speed up JSON serialization (yes, it is slow!) use the `response` key of the
|
|
436
475
|
schema option as shown in the following example:
|
|
437
476
|
```js
|
|
477
|
+
/**
|
|
478
|
+
* @type {import('fastify').RouteShorthandOptions}
|
|
479
|
+
* @const
|
|
480
|
+
*/
|
|
438
481
|
const opts = {
|
|
439
482
|
schema: {
|
|
440
483
|
response: {
|
|
@@ -468,6 +511,9 @@ request](../Reference/Request.md) object at `request.body`.
|
|
|
468
511
|
The following example returns the parsed body of a request back to the client:
|
|
469
512
|
|
|
470
513
|
```js
|
|
514
|
+
/**
|
|
515
|
+
* @type {import('fastify').RouteShorthandOptions}
|
|
516
|
+
*/
|
|
471
517
|
const opts = {}
|
|
472
518
|
fastify.post('/', opts, async (request, reply) => {
|
|
473
519
|
return request.body
|
|
@@ -80,9 +80,9 @@ to show that the plugin works as intended. Both
|
|
|
80
80
|
Actions](https://github.com/features/actions) are free for open source projects
|
|
81
81
|
and easy to set up.
|
|
82
82
|
|
|
83
|
-
In addition, you can enable services like [Dependabot](https://dependabot.com/)
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
In addition, you can enable services like [Dependabot](https://dependabot.com/),
|
|
84
|
+
which will help you keep your dependencies up to date and discover if a new
|
|
85
|
+
release of Fastify has some issues with your plugin.
|
|
86
86
|
|
|
87
87
|
## Let's start!
|
|
88
88
|
Awesome, now you know everything you need to know about how to write a good
|
|
@@ -9,4 +9,4 @@ All v3 deprecations have been removed and they will no longer work after upgradi
|
|
|
9
9
|
|
|
10
10
|
### Deprecation of `app.use()`
|
|
11
11
|
|
|
12
|
-
Starting this version of Fastify, we have deprecated the use of `app.use()`. We have decided not to support the use of middlewares. Both [`middie`](https://github.com/fastify/middie) and [`@fastify/express`](https://github.com/fastify/fastify-express) will still be there and maintained. Use Fastify's [hooks](./Hooks.md) instead.
|
|
12
|
+
Starting this version of Fastify, we have deprecated the use of `app.use()`. We have decided not to support the use of middlewares. Both [`middie`](https://github.com/fastify/middie) and [`@fastify/express`](https://github.com/fastify/fastify-express) will still be there and maintained. Use Fastify's [hooks](./Reference/Hooks.md) instead.
|
package/docs/Reference/Errors.md
CHANGED
|
@@ -17,13 +17,6 @@ way to deal with them is to
|
|
|
17
17
|
[crash](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly).
|
|
18
18
|
|
|
19
19
|
#### Catching Errors In Promises
|
|
20
|
-
In Node.js, unhandled promise rejections (that is, without a `.catch()` handler)
|
|
21
|
-
can also cause memory and file descriptor leaks. While `unhandledRejection` is
|
|
22
|
-
deprecated in Node.js, unhandled rejections will not throw, and still
|
|
23
|
-
potentially leak. You should use a module like
|
|
24
|
-
[`make-promises-safe`](https://github.com/mcollina/make-promises-safe) to ensure
|
|
25
|
-
unhandled rejections _always_ throw.
|
|
26
|
-
|
|
27
20
|
If you are using promises, you should attach a `.catch()` handler synchronously.
|
|
28
21
|
|
|
29
22
|
### Errors In Fastify
|
|
@@ -9,7 +9,7 @@ By default, `register` creates a *new scope*, this means that if you make some
|
|
|
9
9
|
changes to the Fastify instance (via `decorate`), this change will not be
|
|
10
10
|
reflected by the current context ancestors, but only by its descendants. This
|
|
11
11
|
feature allows us to achieve plugin *encapsulation* and *inheritance*, in this
|
|
12
|
-
way we create a *
|
|
12
|
+
way we create a *directed acyclic graph* (DAG) and we will not have issues caused
|
|
13
13
|
by cross dependencies.
|
|
14
14
|
|
|
15
15
|
You may have already seen in the [Getting Started]((../Guides/Getting-Started.md#your-first-plugin)) guide how easy it is to use this API:
|
package/docs/Reference/Routes.md
CHANGED
|
@@ -653,3 +653,24 @@ fastify.route({
|
|
|
653
653
|
}
|
|
654
654
|
})
|
|
655
655
|
```
|
|
656
|
+
|
|
657
|
+
### ⚠ HTTP version check
|
|
658
|
+
|
|
659
|
+
Fastify will check the HTTP version of every request, based on configuration
|
|
660
|
+
options ([http2](./Server.md#http2), [https](./Server.md#https), and
|
|
661
|
+
[serverFactory](./Server.md#serverfactory)), to determine if it matches one or
|
|
662
|
+
all of the > following versions: `2.0`, `1.1`, and `1.0`. If Fastify receives
|
|
663
|
+
a different HTTP version in the request it will return a
|
|
664
|
+
`505 HTTP Version Not Supported` error.
|
|
665
|
+
|
|
666
|
+
| | 2.0 | 1.1 | 1.0 | skip |
|
|
667
|
+
|:------------------------:|:---:|:---:|:---:|:----:|
|
|
668
|
+
| http2 | ✓ | | | |
|
|
669
|
+
| http2 + https | ✓ | | | |
|
|
670
|
+
| http2 + https.allowHTTP1 | ✓ | ✓ | ✓ | |
|
|
671
|
+
| https | | ✓ | ✓ | |
|
|
672
|
+
| http | | ✓ | ✓ | |
|
|
673
|
+
| serverFactory | | | | ✓ |
|
|
674
|
+
|
|
675
|
+
Note: The internal HTTP version check will be removed in the future when Node
|
|
676
|
+
implements [this feature](https://github.com/nodejs/node/issues/43115).
|
package/docs/Reference/Server.md
CHANGED
|
@@ -54,7 +54,7 @@ describes the properties available in that options object.
|
|
|
54
54
|
- [routing](#routing)
|
|
55
55
|
- [route](#route)
|
|
56
56
|
- [close](#close)
|
|
57
|
-
- [decorate
|
|
57
|
+
- [decorate\*](#decorate)
|
|
58
58
|
- [register](#register)
|
|
59
59
|
- [addHook](#addhook)
|
|
60
60
|
- [prefix](#prefix)
|
|
@@ -75,6 +75,8 @@ describes the properties available in that options object.
|
|
|
75
75
|
- [schemaController](#schemacontroller)
|
|
76
76
|
- [setNotFoundHandler](#setnotfoundhandler)
|
|
77
77
|
- [setErrorHandler](#seterrorhandler)
|
|
78
|
+
- [addConstraintStrategy](#addconstraintstrategy)
|
|
79
|
+
- [hasConstraintStrategy](#hasconstraintstrategy)
|
|
78
80
|
- [printRoutes](#printroutes)
|
|
79
81
|
- [printPlugins](#printplugins)
|
|
80
82
|
- [addContentTypeParser](#addcontenttypeparser)
|
|
@@ -463,7 +465,7 @@ Defines the label used for the request identifier when logging the request.
|
|
|
463
465
|
<a id="factory-gen-request-id"></a>
|
|
464
466
|
|
|
465
467
|
Function for generating the request-id. It will receive the incoming request as
|
|
466
|
-
a parameter.
|
|
468
|
+
a parameter. This function is expected to be error-free.
|
|
467
469
|
|
|
468
470
|
+ Default: `value of 'request-id' header if provided or monotonically increasing
|
|
469
471
|
integers`
|
|
@@ -588,12 +590,10 @@ constraint strategies in the
|
|
|
588
590
|
```js
|
|
589
591
|
const customVersionStrategy = {
|
|
590
592
|
storage: function () {
|
|
591
|
-
|
|
593
|
+
const versions = {}
|
|
592
594
|
return {
|
|
593
595
|
get: (version) => { return versions[version] || null },
|
|
594
|
-
set: (version, store) => { versions[version] = store }
|
|
595
|
-
del: (version) => { delete versions[version] },
|
|
596
|
-
empty: () => { versions = {} }
|
|
596
|
+
set: (version, store) => { versions[version] = store }
|
|
597
597
|
}
|
|
598
598
|
},
|
|
599
599
|
deriveVersion: (req, ctx) => {
|
|
@@ -952,6 +952,8 @@ Note that the array contains the `fastify.server.address()` too.
|
|
|
952
952
|
#### getDefaultRoute
|
|
953
953
|
<a id="getDefaultRoute"></a>
|
|
954
954
|
|
|
955
|
+
The `defaultRoute` handler handles requests that do not match any URL specified by your Fastify application.
|
|
956
|
+
This defaults to the 404 handler, but can be overridden with [setDefaultRoute](#setdefaultroute).
|
|
955
957
|
Method to get the `defaultRoute` for the server:
|
|
956
958
|
|
|
957
959
|
```js
|
|
@@ -961,6 +963,8 @@ const defaultRoute = fastify.getDefaultRoute()
|
|
|
961
963
|
#### setDefaultRoute
|
|
962
964
|
<a id="setDefaultRoute"></a>
|
|
963
965
|
|
|
966
|
+
**Note**: The default 404 handler, or one set using `setNotFoundHandler`, will never trigger if the default route is overridden.
|
|
967
|
+
Use [setNotFoundHandler](#setnotfoundhandler) if you want to customize 404 handling instead.
|
|
964
968
|
Method to set the `defaultRoute` for the server:
|
|
965
969
|
|
|
966
970
|
```js
|
|
@@ -1349,6 +1353,42 @@ if (statusCode >= 500) {
|
|
|
1349
1353
|
}
|
|
1350
1354
|
```
|
|
1351
1355
|
|
|
1356
|
+
#### addConstraintStrategy
|
|
1357
|
+
<a id="addConstraintStrategy"></a>
|
|
1358
|
+
|
|
1359
|
+
Function to add a custom constraint strategy. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request.
|
|
1360
|
+
|
|
1361
|
+
Add a custom constraint strategy using the `fastify.addConstraintStrategy` method:
|
|
1362
|
+
|
|
1363
|
+
```js
|
|
1364
|
+
const customResponseTypeStrategy = {
|
|
1365
|
+
// strategy name for referencing in the route handler `constraints` options
|
|
1366
|
+
name: 'accept',
|
|
1367
|
+
// storage factory for storing routes in the find-my-way route tree
|
|
1368
|
+
storage: function () {
|
|
1369
|
+
let handlers = {}
|
|
1370
|
+
return {
|
|
1371
|
+
get: (type) => { return handlers[type] || null },
|
|
1372
|
+
set: (type, store) => { handlers[type] = store }
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
// function to get the value of the constraint from each incoming request
|
|
1376
|
+
deriveConstraint: (req, ctx) => {
|
|
1377
|
+
return req.headers['accept']
|
|
1378
|
+
},
|
|
1379
|
+
// optional flag marking if handlers without constraints can match requests that have a value for this constraint
|
|
1380
|
+
mustMatchWhenDerived: true
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
const router = Fastify();
|
|
1384
|
+
router.addConstraintStrategy(customResponseTypeStrategy);
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
#### hasConstraintStrategy
|
|
1388
|
+
<a id="hasConstraintStrategy"></a>
|
|
1389
|
+
|
|
1390
|
+
The `fastify.hasConstraintStrategy(strategyName)` checks if there already exists a custom constraint strategy with the same name.
|
|
1391
|
+
|
|
1352
1392
|
#### printRoutes
|
|
1353
1393
|
<a id="print-routes"></a>
|
|
1354
1394
|
|
|
File without changes
|
|
@@ -183,6 +183,16 @@ Also it has the advantage to use the defined type within your handlers
|
|
|
183
183
|
|
|
184
184
|
Here are some options how to achieve this.
|
|
185
185
|
|
|
186
|
+
#### Fastify Type Providers
|
|
187
|
+
|
|
188
|
+
Fastify offers two packages wrapping `json-schema-to-ts` and `typebox`:
|
|
189
|
+
|
|
190
|
+
- `@fastify/type-provider-json-schema-to-ts`
|
|
191
|
+
- `@fastify/type-provider-typebox`
|
|
192
|
+
|
|
193
|
+
They simplify schema validation setup and you can read more about them in [Type Providers](./Type-Providers.md) page.
|
|
194
|
+
|
|
195
|
+
Below is how to setup schema validation using vanilla `typebox` and `json-schema-to-ts` packages.
|
|
186
196
|
|
|
187
197
|
#### typebox
|
|
188
198
|
|
|
@@ -330,7 +340,7 @@ into TypeScript interfaces!
|
|
|
330
340
|
// or if using async
|
|
331
341
|
// preValidation: async (request, reply) => {
|
|
332
342
|
// const { username, password } = request.query
|
|
333
|
-
//
|
|
343
|
+
// if (username !== "admin") throw new Error("Must be admin");
|
|
334
344
|
// }
|
|
335
345
|
}, async (request, reply) => {
|
|
336
346
|
const customerHeader = request.headers['h-Custom']
|
package/fastify.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '4.0.0-rc.
|
|
3
|
+
const VERSION = '4.0.0-rc.3'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
7
|
-
const querystring = require('querystring')
|
|
8
7
|
let lightMyRequest
|
|
9
8
|
|
|
10
9
|
const {
|
|
@@ -32,7 +31,7 @@ const {
|
|
|
32
31
|
kFourOhFourContext
|
|
33
32
|
} = require('./lib/symbols.js')
|
|
34
33
|
|
|
35
|
-
const createServer = require('./lib/server')
|
|
34
|
+
const { createServer, compileValidateHTTPVersion } = require('./lib/server')
|
|
36
35
|
const Reply = require('./lib/reply')
|
|
37
36
|
const Request = require('./lib/request')
|
|
38
37
|
const supportedMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS']
|
|
@@ -99,7 +98,6 @@ function fastify (options) {
|
|
|
99
98
|
validateBodyLimitOption(options.bodyLimit)
|
|
100
99
|
|
|
101
100
|
const requestIdHeader = options.requestIdHeader || defaultInitOptions.requestIdHeader
|
|
102
|
-
const querystringParser = options.querystringParser || querystring.parse
|
|
103
101
|
const genReqId = options.genReqId || reqIdGenFactory()
|
|
104
102
|
const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
|
|
105
103
|
const bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
|
|
@@ -131,7 +129,6 @@ function fastify (options) {
|
|
|
131
129
|
options.logger = logger
|
|
132
130
|
options.genReqId = genReqId
|
|
133
131
|
options.requestIdHeader = requestIdHeader
|
|
134
|
-
options.querystringParser = querystringParser
|
|
135
132
|
options.requestIdLogLabel = requestIdLogLabel
|
|
136
133
|
options.disableRequestLogging = disableRequestLogging
|
|
137
134
|
options.ajv = ajvOptions
|
|
@@ -140,7 +137,7 @@ function fastify (options) {
|
|
|
140
137
|
const initialConfig = getSecuredInitialConfig(options)
|
|
141
138
|
const keepAliveConnections = options.forceCloseConnections === true ? new Set() : noopSet()
|
|
142
139
|
|
|
143
|
-
// exposeHeadRoutes have its
|
|
140
|
+
// exposeHeadRoutes have its default set from the validator
|
|
144
141
|
options.exposeHeadRoutes = initialConfig.exposeHeadRoutes
|
|
145
142
|
|
|
146
143
|
let constraints = options.constraints
|
|
@@ -172,7 +169,8 @@ function fastify (options) {
|
|
|
172
169
|
maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength,
|
|
173
170
|
caseSensitive: options.caseSensitive,
|
|
174
171
|
allowUnsafeRegex: options.allowUnsafeRegex || defaultInitOptions.allowUnsafeRegex,
|
|
175
|
-
buildPrettyMeta: defaultBuildPrettyMeta
|
|
172
|
+
buildPrettyMeta: defaultBuildPrettyMeta,
|
|
173
|
+
querystringParser: options.querystringParser
|
|
176
174
|
},
|
|
177
175
|
keepAliveConnections
|
|
178
176
|
})
|
|
@@ -310,7 +308,10 @@ function fastify (options) {
|
|
|
310
308
|
setNotFoundHandler,
|
|
311
309
|
setErrorHandler,
|
|
312
310
|
// Set fastify initial configuration options read-only object
|
|
313
|
-
initialConfig
|
|
311
|
+
initialConfig,
|
|
312
|
+
// constraint strategies
|
|
313
|
+
addConstraintStrategy: router.addConstraintStrategy.bind(router),
|
|
314
|
+
hasConstraintStrategy: router.hasConstraintStrategy.bind(router)
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
Object.defineProperties(fastify, {
|
|
@@ -408,7 +409,8 @@ function fastify (options) {
|
|
|
408
409
|
logger,
|
|
409
410
|
hasLogger,
|
|
410
411
|
setupResponseListeners,
|
|
411
|
-
throwIfAlreadyStarted
|
|
412
|
+
throwIfAlreadyStarted,
|
|
413
|
+
validateHTTPVersion: compileValidateHTTPVersion(options)
|
|
412
414
|
})
|
|
413
415
|
|
|
414
416
|
// Delay configuring clientError handler so that it can access fastify state.
|
|
@@ -607,7 +609,7 @@ function fastify (options) {
|
|
|
607
609
|
if (req.headers['accept-version'] !== undefined) {
|
|
608
610
|
// we remove the accept-version header for performance result
|
|
609
611
|
// because we do not want to go through the constraint checking
|
|
610
|
-
// the usage of symbol here to prevent any
|
|
612
|
+
// the usage of symbol here to prevent any collision on custom header name
|
|
611
613
|
req.headers[kRequestAcceptVersion] = req.headers['accept-version']
|
|
612
614
|
req.headers['accept-version'] = undefined
|
|
613
615
|
}
|
package/lib/hooks.js
CHANGED
package/lib/pluginUtils.js
CHANGED
|
@@ -103,8 +103,8 @@ function checkVersion (fn) {
|
|
|
103
103
|
|
|
104
104
|
const requiredVersion = meta.fastify
|
|
105
105
|
|
|
106
|
-
const
|
|
107
|
-
if (requiredVersion &&
|
|
106
|
+
const fastifyRc = /-rc.+$/.test(this.version)
|
|
107
|
+
if (requiredVersion && semver.satisfies(this.version, requiredVersion, { includePrerelease: fastifyRc }) === false) {
|
|
108
108
|
throw new FST_ERR_PLUGIN_VERSION_MISMATCH(meta.name, requiredVersion, this.version)
|
|
109
109
|
}
|
|
110
110
|
}
|
package/lib/route.js
CHANGED
|
@@ -20,7 +20,8 @@ const {
|
|
|
20
20
|
FST_ERR_SCH_SERIALIZATION_BUILD,
|
|
21
21
|
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
|
|
22
22
|
FST_ERR_DUPLICATED_ROUTE,
|
|
23
|
-
FST_ERR_INVALID_URL
|
|
23
|
+
FST_ERR_INVALID_URL,
|
|
24
|
+
FST_ERR_SEND_UNDEFINED_ERR
|
|
24
25
|
} = require('./errors')
|
|
25
26
|
|
|
26
27
|
const {
|
|
@@ -47,7 +48,6 @@ function buildRouting (options) {
|
|
|
47
48
|
let avvio
|
|
48
49
|
let fourOhFour
|
|
49
50
|
let requestIdHeader
|
|
50
|
-
let querystringParser
|
|
51
51
|
let requestIdLogLabel
|
|
52
52
|
let logger
|
|
53
53
|
let hasLogger
|
|
@@ -58,6 +58,7 @@ function buildRouting (options) {
|
|
|
58
58
|
let ignoreTrailingSlash
|
|
59
59
|
let return503OnClosing
|
|
60
60
|
let globalExposeHeadRoutes
|
|
61
|
+
let validateHTTPVersion
|
|
61
62
|
|
|
62
63
|
let closing = false
|
|
63
64
|
|
|
@@ -69,10 +70,10 @@ function buildRouting (options) {
|
|
|
69
70
|
hasLogger = fastifyArgs.hasLogger
|
|
70
71
|
setupResponseListeners = fastifyArgs.setupResponseListeners
|
|
71
72
|
throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
|
|
73
|
+
validateHTTPVersion = fastifyArgs.validateHTTPVersion
|
|
72
74
|
|
|
73
75
|
globalExposeHeadRoutes = options.exposeHeadRoutes
|
|
74
76
|
requestIdHeader = options.requestIdHeader
|
|
75
|
-
querystringParser = options.querystringParser
|
|
76
77
|
requestIdLogLabel = options.requestIdLogLabel
|
|
77
78
|
genReqId = options.genReqId
|
|
78
79
|
disableRequestLogging = options.disableRequestLogging
|
|
@@ -94,7 +95,18 @@ function buildRouting (options) {
|
|
|
94
95
|
},
|
|
95
96
|
routeHandler,
|
|
96
97
|
closeRoutes: () => { closing = true },
|
|
97
|
-
printRoutes: router.prettyPrint.bind(router)
|
|
98
|
+
printRoutes: router.prettyPrint.bind(router),
|
|
99
|
+
addConstraintStrategy,
|
|
100
|
+
hasConstraintStrategy
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function addConstraintStrategy (strategy) {
|
|
104
|
+
throwIfAlreadyStarted('Cannot add constraint strategy when fastify instance is already started!')
|
|
105
|
+
return router.addConstraintStrategy(strategy)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function hasConstraintStrategy (strategyName) {
|
|
109
|
+
return router.hasConstraintStrategy(strategyName)
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
// Convert shorthand to extended route declaration
|
|
@@ -322,7 +334,19 @@ function buildRouting (options) {
|
|
|
322
334
|
}
|
|
323
335
|
|
|
324
336
|
// HTTP request entry point, the routing has already been executed
|
|
325
|
-
function routeHandler (req, res, params, context) {
|
|
337
|
+
function routeHandler (req, res, params, context, query) {
|
|
338
|
+
// TODO: The check here should be removed once https://github.com/nodejs/node/issues/43115 resolve in core.
|
|
339
|
+
if (!validateHTTPVersion(req.httpVersion)) {
|
|
340
|
+
const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
|
|
341
|
+
const headers = {
|
|
342
|
+
'Content-Type': 'application/json',
|
|
343
|
+
'Content-Length': message.length
|
|
344
|
+
}
|
|
345
|
+
res.writeHead(505, headers)
|
|
346
|
+
res.end(message)
|
|
347
|
+
return
|
|
348
|
+
}
|
|
349
|
+
|
|
326
350
|
if (closing === true) {
|
|
327
351
|
/* istanbul ignore next mac, windows */
|
|
328
352
|
if (req.httpVersionMajor !== 2) {
|
|
@@ -374,8 +398,6 @@ function buildRouting (options) {
|
|
|
374
398
|
const childLogger = logger.child(loggerBinding, loggerOpts)
|
|
375
399
|
childLogger[kDisableRequestLogging] = disableRequestLogging
|
|
376
400
|
|
|
377
|
-
const queryPrefix = req.url.indexOf('?')
|
|
378
|
-
const query = querystringParser(queryPrefix > -1 ? req.url.slice(queryPrefix + 1) : '')
|
|
379
401
|
const request = new context.Request(id, params, req, query, childLogger, context)
|
|
380
402
|
const reply = new context.Reply(res, request, childLogger)
|
|
381
403
|
|
|
@@ -489,6 +511,10 @@ function preParsingHookRunner (functions, request, reply, cb) {
|
|
|
489
511
|
}
|
|
490
512
|
|
|
491
513
|
function handleReject (err) {
|
|
514
|
+
if (!err) {
|
|
515
|
+
err = new FST_ERR_SEND_UNDEFINED_ERR()
|
|
516
|
+
}
|
|
517
|
+
|
|
492
518
|
next(err)
|
|
493
519
|
}
|
|
494
520
|
|
package/lib/server.js
CHANGED
|
@@ -8,7 +8,8 @@ const warnings = require('./warnings')
|
|
|
8
8
|
const { kState, kOptions, kServerBindings } = require('./symbols')
|
|
9
9
|
const { FST_ERR_HTTP2_INVALID_VERSION, FST_ERR_REOPENED_CLOSE_SERVER, FST_ERR_REOPENED_SERVER } = require('./errors')
|
|
10
10
|
|
|
11
|
-
module.exports = createServer
|
|
11
|
+
module.exports.createServer = createServer
|
|
12
|
+
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion
|
|
12
13
|
|
|
13
14
|
function createServer (options, httpHandler) {
|
|
14
15
|
const server = getServerInstance(options, httpHandler)
|
|
@@ -208,6 +209,56 @@ function listenPromise (server, listenOptions) {
|
|
|
208
209
|
})
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Creates a function that, based upon initial configuration, will
|
|
214
|
+
* verify that every incoming request conforms to allowed
|
|
215
|
+
* HTTP versions for the Fastify instance, e.g. a Fastify HTTP/1.1
|
|
216
|
+
* server will not serve HTTP/2 requests upon the result of the
|
|
217
|
+
* verification function.
|
|
218
|
+
*
|
|
219
|
+
* @param {object} options fastify option
|
|
220
|
+
* @param {function} [options.serverFactory] If present, the
|
|
221
|
+
* validator function will skip all checks.
|
|
222
|
+
* @param {boolean} [options.http2 = false] If true, the validator
|
|
223
|
+
* function will allow HTTP/2 requests.
|
|
224
|
+
* @param {object} [options.https = null] https server options
|
|
225
|
+
* @param {boolean} [options.https.allowHTTP1] If true and use
|
|
226
|
+
* with options.http2 the validator function will allow HTTP/1
|
|
227
|
+
* request to http2 server.
|
|
228
|
+
*
|
|
229
|
+
* @returns {function} HTTP version validator function.
|
|
230
|
+
*/
|
|
231
|
+
function compileValidateHTTPVersion (options) {
|
|
232
|
+
let bypass = false
|
|
233
|
+
// key-value map to store valid http version
|
|
234
|
+
const map = new Map()
|
|
235
|
+
if (options.serverFactory) {
|
|
236
|
+
// When serverFactory is passed, we cannot identify how to check http version reliably
|
|
237
|
+
// So, we should skip the http version check
|
|
238
|
+
bypass = true
|
|
239
|
+
}
|
|
240
|
+
if (options.http2) {
|
|
241
|
+
// HTTP2 must serve HTTP/2.0
|
|
242
|
+
map.set('2.0', true)
|
|
243
|
+
if (options.https && options.https.allowHTTP1 === true) {
|
|
244
|
+
// HTTP2 with HTTPS.allowHTTP1 allow fallback to HTTP/1.1 and HTTP/1.0
|
|
245
|
+
map.set('1.1', true)
|
|
246
|
+
map.set('1.0', true)
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
// HTTP must server HTTP/1.1 and HTTP/1.0
|
|
250
|
+
map.set('1.1', true)
|
|
251
|
+
map.set('1.0', true)
|
|
252
|
+
}
|
|
253
|
+
// The compiled function here placed in one of the hottest path inside fastify
|
|
254
|
+
// the implementation here must be as performant as possible
|
|
255
|
+
return function validateHTTPVersion (httpVersion) {
|
|
256
|
+
// `bypass` skip the check when custom server factory provided
|
|
257
|
+
// `httpVersion in obj` check for the valid http version we should support
|
|
258
|
+
return bypass || map.has(httpVersion)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
211
262
|
function getServerInstance (options, httpHandler) {
|
|
212
263
|
let server = null
|
|
213
264
|
if (options.serverFactory) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "4.0.0-rc.
|
|
3
|
+
"version": "4.0.0-rc.3",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
"@fastify/fast-json-stringify-compiler": "^1.0.0",
|
|
181
181
|
"abstract-logging": "^2.0.1",
|
|
182
182
|
"avvio": "^8.1.0",
|
|
183
|
-
"find-my-way": "^
|
|
183
|
+
"find-my-way": "^6.0.0",
|
|
184
184
|
"light-my-request": "^4.7.0",
|
|
185
185
|
"pino": "^7.5.1",
|
|
186
186
|
"process-warning": "^1.0.0",
|
|
@@ -113,12 +113,10 @@ test('Should allow registering custom constrained routes', t => {
|
|
|
113
113
|
const constraint = {
|
|
114
114
|
name: 'secret',
|
|
115
115
|
storage: function () {
|
|
116
|
-
|
|
116
|
+
const secrets = {}
|
|
117
117
|
return {
|
|
118
118
|
get: (secret) => { return secrets[secret] || null },
|
|
119
|
-
set: (secret, store) => { secrets[secret] = store }
|
|
120
|
-
del: (secret) => { delete secrets[secret] },
|
|
121
|
-
empty: () => { secrets = {} }
|
|
119
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
122
120
|
}
|
|
123
121
|
},
|
|
124
122
|
deriveConstraint: (req, ctx) => {
|
|
@@ -183,6 +181,266 @@ test('Should allow registering custom constrained routes', t => {
|
|
|
183
181
|
})
|
|
184
182
|
})
|
|
185
183
|
|
|
184
|
+
test('Should allow registering custom constrained routes outside constructor', t => {
|
|
185
|
+
t.plan(8)
|
|
186
|
+
|
|
187
|
+
const constraint = {
|
|
188
|
+
name: 'secret',
|
|
189
|
+
storage: function () {
|
|
190
|
+
const secrets = {}
|
|
191
|
+
return {
|
|
192
|
+
get: (secret) => { return secrets[secret] || null },
|
|
193
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
deriveConstraint: (req, ctx) => {
|
|
197
|
+
return req.headers['x-secret']
|
|
198
|
+
},
|
|
199
|
+
validate () { return true }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const fastify = Fastify()
|
|
203
|
+
fastify.addConstraintStrategy(constraint)
|
|
204
|
+
|
|
205
|
+
fastify.route({
|
|
206
|
+
method: 'GET',
|
|
207
|
+
url: '/',
|
|
208
|
+
constraints: { secret: 'alpha' },
|
|
209
|
+
handler: (req, reply) => {
|
|
210
|
+
reply.send({ hello: 'from alpha' })
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
fastify.route({
|
|
215
|
+
method: 'GET',
|
|
216
|
+
url: '/',
|
|
217
|
+
constraints: { secret: 'beta' },
|
|
218
|
+
handler: (req, reply) => {
|
|
219
|
+
reply.send({ hello: 'from beta' })
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
fastify.inject({
|
|
224
|
+
method: 'GET',
|
|
225
|
+
url: '/',
|
|
226
|
+
headers: {
|
|
227
|
+
'X-Secret': 'alpha'
|
|
228
|
+
}
|
|
229
|
+
}, (err, res) => {
|
|
230
|
+
t.error(err)
|
|
231
|
+
t.same(JSON.parse(res.payload), { hello: 'from alpha' })
|
|
232
|
+
t.equal(res.statusCode, 200)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
fastify.inject({
|
|
236
|
+
method: 'GET',
|
|
237
|
+
url: '/',
|
|
238
|
+
headers: {
|
|
239
|
+
'X-Secret': 'beta'
|
|
240
|
+
}
|
|
241
|
+
}, (err, res) => {
|
|
242
|
+
t.error(err)
|
|
243
|
+
t.same(JSON.parse(res.payload), { hello: 'from beta' })
|
|
244
|
+
t.equal(res.statusCode, 200)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
fastify.inject({
|
|
248
|
+
method: 'GET',
|
|
249
|
+
url: '/',
|
|
250
|
+
headers: {
|
|
251
|
+
'X-Secret': 'gamma'
|
|
252
|
+
}
|
|
253
|
+
}, (err, res) => {
|
|
254
|
+
t.error(err)
|
|
255
|
+
t.equal(res.statusCode, 404)
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
test('Add a constraint strategy after fastify instance was started', t => {
|
|
260
|
+
t.plan(4)
|
|
261
|
+
|
|
262
|
+
const constraint = {
|
|
263
|
+
name: 'secret',
|
|
264
|
+
storage: function () {
|
|
265
|
+
const secrets = {}
|
|
266
|
+
return {
|
|
267
|
+
get: (secret) => { return secrets[secret] || null },
|
|
268
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
deriveConstraint: (req, ctx) => {
|
|
272
|
+
return req.headers['x-secret']
|
|
273
|
+
},
|
|
274
|
+
validate () { return true }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const fastify = Fastify()
|
|
278
|
+
|
|
279
|
+
fastify.route({
|
|
280
|
+
method: 'GET',
|
|
281
|
+
url: '/',
|
|
282
|
+
handler: (req, reply) => { reply.send('ok') }
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
fastify.inject({
|
|
286
|
+
method: 'GET',
|
|
287
|
+
url: '/'
|
|
288
|
+
}, (err, res) => {
|
|
289
|
+
t.error(err)
|
|
290
|
+
t.same(res.payload, 'ok')
|
|
291
|
+
t.equal(res.statusCode, 200)
|
|
292
|
+
|
|
293
|
+
t.throws(
|
|
294
|
+
() => fastify.addConstraintStrategy(constraint),
|
|
295
|
+
'Cannot add constraint strategy when fastify instance is already started!'
|
|
296
|
+
)
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
test('Add a constraint strategy should throw an error if there already exist custom strategy with the same name', t => {
|
|
301
|
+
t.plan(1)
|
|
302
|
+
|
|
303
|
+
const constraint = {
|
|
304
|
+
name: 'secret',
|
|
305
|
+
storage: function () {
|
|
306
|
+
const secrets = {}
|
|
307
|
+
return {
|
|
308
|
+
get: (secret) => { return secrets[secret] || null },
|
|
309
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
deriveConstraint: (req, ctx) => {
|
|
313
|
+
return req.headers['x-secret']
|
|
314
|
+
},
|
|
315
|
+
validate () { return true }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const fastify = Fastify()
|
|
319
|
+
|
|
320
|
+
fastify.addConstraintStrategy(constraint)
|
|
321
|
+
t.throws(
|
|
322
|
+
() => fastify.addConstraintStrategy(constraint),
|
|
323
|
+
'There already exists a custom constraint with the name secret.'
|
|
324
|
+
)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
test('Add a constraint strategy shouldn\'t throw an error if default constraint with the same name isn\'t used', t => {
|
|
328
|
+
t.plan(1)
|
|
329
|
+
|
|
330
|
+
const constraint = {
|
|
331
|
+
name: 'version',
|
|
332
|
+
storage: function () {
|
|
333
|
+
const secrets = {}
|
|
334
|
+
return {
|
|
335
|
+
get: (secret) => { return secrets[secret] || null },
|
|
336
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
deriveConstraint: (req, ctx) => {
|
|
340
|
+
return req.headers['x-secret']
|
|
341
|
+
},
|
|
342
|
+
validate () { return true }
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const fastify = Fastify()
|
|
346
|
+
fastify.addConstraintStrategy(constraint)
|
|
347
|
+
|
|
348
|
+
t.pass()
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
test('Add a constraint strategy should throw an error if default constraint with the same name is used', t => {
|
|
352
|
+
t.plan(1)
|
|
353
|
+
|
|
354
|
+
const constraint = {
|
|
355
|
+
name: 'version',
|
|
356
|
+
storage: function () {
|
|
357
|
+
const secrets = {}
|
|
358
|
+
return {
|
|
359
|
+
get: (secret) => { return secrets[secret] || null },
|
|
360
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
deriveConstraint: (req, ctx) => {
|
|
364
|
+
return req.headers['x-secret']
|
|
365
|
+
},
|
|
366
|
+
validate () { return true }
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const fastify = Fastify()
|
|
370
|
+
|
|
371
|
+
fastify.route({
|
|
372
|
+
method: 'GET',
|
|
373
|
+
url: '/',
|
|
374
|
+
constraints: { version: '1.0.0' },
|
|
375
|
+
handler: (req, reply) => {
|
|
376
|
+
reply.send('ok')
|
|
377
|
+
}
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
t.throws(
|
|
381
|
+
() => fastify.addConstraintStrategy(constraint),
|
|
382
|
+
'There already exists a route with version constraint.'
|
|
383
|
+
)
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
test('The hasConstraintStrategy should return false for default constraints until they are used', t => {
|
|
387
|
+
t.plan(6)
|
|
388
|
+
|
|
389
|
+
const fastify = Fastify()
|
|
390
|
+
|
|
391
|
+
t.equal(fastify.hasConstraintStrategy('version'), false)
|
|
392
|
+
t.equal(fastify.hasConstraintStrategy('host'), false)
|
|
393
|
+
|
|
394
|
+
fastify.route({
|
|
395
|
+
method: 'GET',
|
|
396
|
+
url: '/',
|
|
397
|
+
constraints: { host: 'fastify.io' },
|
|
398
|
+
handler: (req, reply) => {
|
|
399
|
+
reply.send({ hello: 'from any other domain' })
|
|
400
|
+
}
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
t.equal(fastify.hasConstraintStrategy('version'), false)
|
|
404
|
+
t.equal(fastify.hasConstraintStrategy('host'), true)
|
|
405
|
+
|
|
406
|
+
fastify.route({
|
|
407
|
+
method: 'GET',
|
|
408
|
+
url: '/',
|
|
409
|
+
constraints: { version: '1.0.0' },
|
|
410
|
+
handler: (req, reply) => {
|
|
411
|
+
reply.send({ hello: 'from any other domain' })
|
|
412
|
+
}
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
t.equal(fastify.hasConstraintStrategy('version'), true)
|
|
416
|
+
t.equal(fastify.hasConstraintStrategy('host'), true)
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
test('The hasConstraintStrategy should return true if there already exist a custom constraint with the same name', t => {
|
|
420
|
+
t.plan(2)
|
|
421
|
+
|
|
422
|
+
const constraint = {
|
|
423
|
+
name: 'secret',
|
|
424
|
+
storage: function () {
|
|
425
|
+
const secrets = {}
|
|
426
|
+
return {
|
|
427
|
+
get: (secret) => { return secrets[secret] || null },
|
|
428
|
+
set: (secret, store) => { secrets[secret] = store }
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
deriveConstraint: (req, ctx) => {
|
|
432
|
+
return req.headers['x-secret']
|
|
433
|
+
},
|
|
434
|
+
validate () { return true }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const fastify = Fastify()
|
|
438
|
+
|
|
439
|
+
t.equal(fastify.hasConstraintStrategy('secret'), false)
|
|
440
|
+
fastify.addConstraintStrategy(constraint)
|
|
441
|
+
t.equal(fastify.hasConstraintStrategy('secret'), true)
|
|
442
|
+
})
|
|
443
|
+
|
|
186
444
|
test('Should allow registering an unconstrained route after a constrained route', t => {
|
|
187
445
|
t.plan(6)
|
|
188
446
|
const fastify = Fastify()
|
package/test/hooks.test.js
CHANGED
|
@@ -3146,6 +3146,64 @@ test('reply.send should throw if undefined error is thrown', t => {
|
|
|
3146
3146
|
})
|
|
3147
3147
|
})
|
|
3148
3148
|
|
|
3149
|
+
test('reply.send should throw if undefined error is thrown at preParsing hook', t => {
|
|
3150
|
+
/* eslint prefer-promise-reject-errors: ["error", {"allowEmptyReject": true}] */
|
|
3151
|
+
|
|
3152
|
+
t.plan(3)
|
|
3153
|
+
const fastify = Fastify()
|
|
3154
|
+
|
|
3155
|
+
fastify.addHook('preParsing', function (req, reply, done) {
|
|
3156
|
+
return Promise.reject()
|
|
3157
|
+
})
|
|
3158
|
+
|
|
3159
|
+
fastify.get('/', (req, reply) => {
|
|
3160
|
+
reply.send('hello')
|
|
3161
|
+
})
|
|
3162
|
+
|
|
3163
|
+
fastify.inject({
|
|
3164
|
+
method: 'GET',
|
|
3165
|
+
url: '/'
|
|
3166
|
+
}, (err, res) => {
|
|
3167
|
+
t.error(err)
|
|
3168
|
+
t.equal(res.statusCode, 500)
|
|
3169
|
+
t.same(JSON.parse(res.payload), {
|
|
3170
|
+
error: 'Internal Server Error',
|
|
3171
|
+
code: 'FST_ERR_SEND_UNDEFINED_ERR',
|
|
3172
|
+
message: 'Undefined error has occurred',
|
|
3173
|
+
statusCode: 500
|
|
3174
|
+
})
|
|
3175
|
+
})
|
|
3176
|
+
})
|
|
3177
|
+
|
|
3178
|
+
test('reply.send should throw if undefined error is thrown at onSend hook', t => {
|
|
3179
|
+
/* eslint prefer-promise-reject-errors: ["error", {"allowEmptyReject": true}] */
|
|
3180
|
+
|
|
3181
|
+
t.plan(3)
|
|
3182
|
+
const fastify = Fastify()
|
|
3183
|
+
|
|
3184
|
+
fastify.addHook('onSend', function (req, reply, done) {
|
|
3185
|
+
return Promise.reject()
|
|
3186
|
+
})
|
|
3187
|
+
|
|
3188
|
+
fastify.get('/', (req, reply) => {
|
|
3189
|
+
reply.send('hello')
|
|
3190
|
+
})
|
|
3191
|
+
|
|
3192
|
+
fastify.inject({
|
|
3193
|
+
method: 'GET',
|
|
3194
|
+
url: '/'
|
|
3195
|
+
}, (err, res) => {
|
|
3196
|
+
t.error(err)
|
|
3197
|
+
t.equal(res.statusCode, 500)
|
|
3198
|
+
t.same(JSON.parse(res.payload), {
|
|
3199
|
+
error: 'Internal Server Error',
|
|
3200
|
+
code: 'FST_ERR_SEND_UNDEFINED_ERR',
|
|
3201
|
+
message: 'Undefined error has occurred',
|
|
3202
|
+
statusCode: 500
|
|
3203
|
+
})
|
|
3204
|
+
})
|
|
3205
|
+
})
|
|
3206
|
+
|
|
3149
3207
|
test('onTimeout should be triggered', t => {
|
|
3150
3208
|
t.plan(6)
|
|
3151
3209
|
const fastify = Fastify({ connectionTimeout: 500 })
|
|
@@ -68,12 +68,10 @@ test('Fastify.initialConfig should expose all options', t => {
|
|
|
68
68
|
const versionStrategy = {
|
|
69
69
|
name: 'version',
|
|
70
70
|
storage: function () {
|
|
71
|
-
|
|
71
|
+
const versions = {}
|
|
72
72
|
return {
|
|
73
73
|
get: (version) => { return versions[version] || null },
|
|
74
|
-
set: (version, store) => { versions[version] = store }
|
|
75
|
-
del: (version) => { delete versions[version] },
|
|
76
|
-
empty: () => { versions = {} }
|
|
74
|
+
set: (version, store) => { versions[version] = store }
|
|
77
75
|
}
|
|
78
76
|
},
|
|
79
77
|
deriveConstraint: (req, ctx) => {
|
|
@@ -362,12 +360,10 @@ test('Fastify.initialConfig should accept the deprecated versioning option', t =
|
|
|
362
360
|
|
|
363
361
|
const versioning = {
|
|
364
362
|
storage: function () {
|
|
365
|
-
|
|
363
|
+
const versions = {}
|
|
366
364
|
return {
|
|
367
365
|
get: (version) => { return versions[version] || null },
|
|
368
|
-
set: (version, store) => { versions[version] = store }
|
|
369
|
-
del: (version) => { delete versions[version] },
|
|
370
|
-
empty: () => { versions = {} }
|
|
366
|
+
set: (version, store) => { versions[version] = store }
|
|
371
367
|
}
|
|
372
368
|
},
|
|
373
369
|
deriveVersion: (req, ctx) => {
|
|
@@ -4,7 +4,7 @@ const { test } = require('tap')
|
|
|
4
4
|
const proxyquire = require('proxyquire')
|
|
5
5
|
|
|
6
6
|
const Fastify = require('../../fastify')
|
|
7
|
-
const createServer = require('../../lib/server')
|
|
7
|
+
const { createServer } = require('../../lib/server')
|
|
8
8
|
|
|
9
9
|
const handler = (req, res) => {
|
|
10
10
|
res.writeHead(200, { 'Content-Type': 'application/json' })
|
|
@@ -19,7 +19,7 @@ test('start listening', async t => {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
test('DNS errors does not stop the main server on localhost - promise interface', async t => {
|
|
22
|
-
const createServer = proxyquire('../../lib/server', {
|
|
22
|
+
const { createServer } = proxyquire('../../lib/server', {
|
|
23
23
|
dns: {
|
|
24
24
|
lookup: (hostname, options, cb) => {
|
|
25
25
|
cb(new Error('DNS error'))
|
|
@@ -34,7 +34,7 @@ test('DNS errors does not stop the main server on localhost - promise interface'
|
|
|
34
34
|
|
|
35
35
|
test('DNS errors does not stop the main server on localhost - callback interface', t => {
|
|
36
36
|
t.plan(2)
|
|
37
|
-
const createServer = proxyquire('../../lib/server', {
|
|
37
|
+
const { createServer } = proxyquire('../../lib/server', {
|
|
38
38
|
dns: {
|
|
39
39
|
lookup: (hostname, options, cb) => {
|
|
40
40
|
cb(new Error('DNS error'))
|
|
@@ -51,7 +51,7 @@ test('DNS errors does not stop the main server on localhost - callback interface
|
|
|
51
51
|
|
|
52
52
|
test('DNS returns empty binding', t => {
|
|
53
53
|
t.plan(2)
|
|
54
|
-
const createServer = proxyquire('../../lib/server', {
|
|
54
|
+
const { createServer } = proxyquire('../../lib/server', {
|
|
55
55
|
dns: {
|
|
56
56
|
lookup: (hostname, options, cb) => {
|
|
57
57
|
cb(null, [])
|
|
@@ -68,7 +68,7 @@ test('DNS returns empty binding', t => {
|
|
|
68
68
|
|
|
69
69
|
test('DNS returns more than two binding', t => {
|
|
70
70
|
t.plan(2)
|
|
71
|
-
const createServer = proxyquire('../../lib/server', {
|
|
71
|
+
const { createServer } = proxyquire('../../lib/server', {
|
|
72
72
|
dns: {
|
|
73
73
|
lookup: (hostname, options, cb) => {
|
|
74
74
|
cb(null, [
|
package/test/listen.test.js
CHANGED
|
@@ -7,7 +7,6 @@ const { test, before } = require('tap')
|
|
|
7
7
|
const dns = require('dns').promises
|
|
8
8
|
const dnsCb = require('dns')
|
|
9
9
|
const sget = require('simple-get').concat
|
|
10
|
-
const semver = require('semver')
|
|
11
10
|
const Fastify = require('..')
|
|
12
11
|
|
|
13
12
|
let localhost
|
|
@@ -372,12 +371,19 @@ test('addresses getter', async t => {
|
|
|
372
371
|
const localAddresses = await dns.lookup('localhost', { all: true })
|
|
373
372
|
for (const address of localAddresses) {
|
|
374
373
|
address.port = port
|
|
375
|
-
if (
|
|
374
|
+
if (typeof address.family === 'number') {
|
|
375
|
+
address.family = 'IPv' + address.family
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const appAddresses = app.addresses()
|
|
379
|
+
for (const address of appAddresses) {
|
|
380
|
+
if (typeof address.family === 'number') {
|
|
376
381
|
address.family = 'IPv' + address.family
|
|
377
382
|
}
|
|
378
383
|
}
|
|
379
384
|
localAddresses.sort((a, b) => a.address.localeCompare(b.address))
|
|
380
|
-
|
|
385
|
+
appAddresses.sort((a, b) => a.address.localeCompare(b.address))
|
|
386
|
+
t.same(appAddresses, localAddresses, 'after listen')
|
|
381
387
|
|
|
382
388
|
await app.close()
|
|
383
389
|
t.same(app.addresses(), [], 'after close')
|
|
@@ -10,6 +10,7 @@ import fastify, {
|
|
|
10
10
|
import { HookHandlerDoneFunction } from '../../types/hooks'
|
|
11
11
|
import { FastifyReply } from '../../types/reply'
|
|
12
12
|
import { FastifyRequest } from '../../types/request'
|
|
13
|
+
import { DefaultRoute } from '../../types/route'
|
|
13
14
|
import { FastifySchemaControllerOptions } from '../../types/schema'
|
|
14
15
|
|
|
15
16
|
const server = fastify()
|
|
@@ -307,3 +308,19 @@ expectError(server.decorate<string>('test', true))
|
|
|
307
308
|
expectError(server.decorate<(myNumber: number) => number>('test', function (myNumber: number): string {
|
|
308
309
|
return ''
|
|
309
310
|
}))
|
|
311
|
+
|
|
312
|
+
const versionConstraintStrategy = {
|
|
313
|
+
name: 'version',
|
|
314
|
+
storage: () => ({
|
|
315
|
+
get: () => () => {},
|
|
316
|
+
set: () => { },
|
|
317
|
+
del: () => { },
|
|
318
|
+
empty: () => { }
|
|
319
|
+
}),
|
|
320
|
+
validate () {},
|
|
321
|
+
deriveConstraint: () => 'foo'
|
|
322
|
+
}
|
|
323
|
+
expectType<void>(server.addConstraintStrategy(versionConstraintStrategy))
|
|
324
|
+
expectType<boolean>(server.hasConstraintStrategy(versionConstraintStrategy.name))
|
|
325
|
+
|
|
326
|
+
expectAssignable<DefaultRoute<RawRequestDefaultExpression, RawReplyDefaultExpression>>(server.getDefaultRoute())
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const net = require('net')
|
|
4
|
+
const t = require('tap')
|
|
5
|
+
const Fastify = require('../fastify')
|
|
6
|
+
|
|
7
|
+
t.test('Will return 505 HTTP error if HTTP version (default) is not supported', t => {
|
|
8
|
+
const fastify = Fastify()
|
|
9
|
+
|
|
10
|
+
t.teardown(fastify.close.bind(fastify))
|
|
11
|
+
|
|
12
|
+
fastify.get('/', (req, reply) => {
|
|
13
|
+
reply.send({ hello: 'world' })
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
fastify.listen({ port: 0 }, err => {
|
|
17
|
+
t.error(err)
|
|
18
|
+
|
|
19
|
+
const port = fastify.server.address().port
|
|
20
|
+
const client = net.createConnection({ port }, () => {
|
|
21
|
+
client.write('GET / HTTP/5.1\r\n\r\n')
|
|
22
|
+
|
|
23
|
+
client.once('data', data => {
|
|
24
|
+
t.match(data.toString(), /505 HTTP Version Not Supported/i)
|
|
25
|
+
client.end(() => {
|
|
26
|
+
t.end()
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
t.test('Will return 505 HTTP error if HTTP version (2.0 when server is 1.1) is not supported', t => {
|
|
34
|
+
const fastify = Fastify()
|
|
35
|
+
|
|
36
|
+
t.teardown(fastify.close.bind(fastify))
|
|
37
|
+
|
|
38
|
+
fastify.get('/', (req, reply) => {
|
|
39
|
+
reply.send({ hello: 'world' })
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
fastify.listen({ port: 0 }, err => {
|
|
43
|
+
t.error(err)
|
|
44
|
+
|
|
45
|
+
const port = fastify.server.address().port
|
|
46
|
+
const client = net.createConnection({ port }, () => {
|
|
47
|
+
client.write('GET / HTTP/2.0\r\n\r\n')
|
|
48
|
+
|
|
49
|
+
client.once('data', data => {
|
|
50
|
+
t.match(data.toString(), /505 HTTP Version Not Supported/i)
|
|
51
|
+
client.end(() => {
|
|
52
|
+
t.end()
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
})
|
|
@@ -480,12 +480,10 @@ test('Should register a versioned route with custom versioning strategy', t => {
|
|
|
480
480
|
const customVersioning = {
|
|
481
481
|
name: 'version',
|
|
482
482
|
storage: function () {
|
|
483
|
-
|
|
483
|
+
const versions = {}
|
|
484
484
|
return {
|
|
485
485
|
get: (version) => { return versions[version] || null },
|
|
486
|
-
set: (version, store) => { versions[version] = store }
|
|
487
|
-
del: (version) => { delete versions[version] },
|
|
488
|
-
empty: () => { versions = {} }
|
|
486
|
+
set: (version, store) => { versions[version] = store }
|
|
489
487
|
}
|
|
490
488
|
},
|
|
491
489
|
deriveConstraint: (req, ctx) => {
|
|
@@ -561,12 +559,10 @@ test('Should get error using an invalid a versioned route, using default validat
|
|
|
561
559
|
const fastify = Fastify({
|
|
562
560
|
versioning: {
|
|
563
561
|
storage: function () {
|
|
564
|
-
|
|
562
|
+
const versions = {}
|
|
565
563
|
return {
|
|
566
564
|
get: (version) => { return versions[version] || null },
|
|
567
|
-
set: (version, store) => { versions[version] = store }
|
|
568
|
-
del: (version) => { delete versions[version] },
|
|
569
|
-
empty: () => { versions = {} }
|
|
565
|
+
set: (version, store) => { versions[version] = store }
|
|
570
566
|
}
|
|
571
567
|
},
|
|
572
568
|
deriveVersion: (req, ctx) => {
|
package/types/instance.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import * as http from 'http'
|
|
1
2
|
import { FastifyError } from '@fastify/error'
|
|
3
|
+
import { ConstraintStrategy, HTTPVersion } from 'find-my-way'
|
|
2
4
|
import { CallbackFunc as LightMyRequestCallback, Chain as LightMyRequestChain, InjectOptions, Response as LightMyRequestResponse } from 'light-my-request'
|
|
3
5
|
import { AddContentTypeParser, ConstructorAction, FastifyBodyParser, getDefaultJsonParser, hasContentTypeParser, ProtoAction, removeAllContentTypeParsers, removeContentTypeParser } from './content-type-parser'
|
|
4
6
|
import { onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler } from './hooks'
|
|
@@ -29,6 +31,7 @@ export interface PrintRoutesOptions {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
type NotInInterface<Key, _Interface> = Key extends keyof _Interface ? never : Key
|
|
34
|
+
type FindMyWayVersion<RawServer extends RawServerBase> = RawServer extends http.Server ? HTTPVersion.V1 : HTTPVersion.V2
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* Fastify server instance. Returned by the core `fastify()` method.
|
|
@@ -83,6 +86,9 @@ export interface FastifyInstance<
|
|
|
83
86
|
hasRequestDecorator(decorator: string | symbol): boolean;
|
|
84
87
|
hasReplyDecorator(decorator: string | symbol): boolean;
|
|
85
88
|
|
|
89
|
+
addConstraintStrategy(strategy: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>): void;
|
|
90
|
+
hasConstraintStrategy(strategyName: string): boolean;
|
|
91
|
+
|
|
86
92
|
inject(opts: InjectOptions | string, cb: LightMyRequestCallback): void;
|
|
87
93
|
inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
|
|
88
94
|
inject(): LightMyRequestChain;
|
|
@@ -206,7 +212,7 @@ export interface FastifyInstance<
|
|
|
206
212
|
register: FastifyRegister<FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & PromiseLike<undefined>>;
|
|
207
213
|
|
|
208
214
|
routing(req: RawRequest, res: RawReply): void;
|
|
209
|
-
getDefaultRoute: DefaultRoute<RawRequest, RawReply>;
|
|
215
|
+
getDefaultRoute(): DefaultRoute<RawRequest, RawReply>;
|
|
210
216
|
setDefaultRoute(defaultRoute: DefaultRoute<RawRequest, RawReply>): void;
|
|
211
217
|
|
|
212
218
|
route<
|