fastify 3.24.0 → 3.24.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/docs/Ecosystem.md +2 -0
- package/docs/Getting-Started.md +18 -0
- package/docs/Logging.md +23 -1
- package/docs/Plugins.md +1 -1
- package/docs/Reply.md +16 -3
- package/docs/Serverless.md +123 -0
- package/docs/Validation-and-Serialization.md +1 -1
- package/examples/typescript-server.ts +1 -1
- package/fastify.js +2 -3
- package/lib/logger.js +1 -1
- package/lib/server.js +9 -8
- package/package.json +2 -2
- package/test/logger.test.js +16 -0
- package/test/maxRequestsPerSocket.test.js +10 -0
- package/test/requestTimeout.test.js +4 -1
- package/test/schema-feature.test.js +146 -0
- package/test/types/instance.test-d.ts +6 -0
- package/test/types/request.test-d.ts +7 -1
- package/test/types/route.test-d.ts +21 -0
- package/types/instance.d.ts +4 -4
- package/types/request.d.ts +4 -1
- package/types/route.d.ts +1 -1
package/docs/Ecosystem.md
CHANGED
|
@@ -91,6 +91,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
|
|
|
91
91
|
- [`fastify-cloudevents`](https://github.com/smartiniOnGitHub/fastify-cloudevents) Fastify plugin to generate and forward Fastify events in the Cloudevents format.
|
|
92
92
|
- [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb) Fastify plugin to connect to a CockroachDB PostgreSQL instance via the Sequelize ORM.
|
|
93
93
|
- [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify plugin to add CouchDB support via [nano](https://github.com/apache/nano).
|
|
94
|
+
- [`fastify-crud-generator`](https://github.com/heply/fastify-crud-generator) A plugin to rapidly generate CRUD routes for any entity.
|
|
94
95
|
- [`fastify-custom-healthcheck`](https://github.com/gkampitakis/fastify-custom-healthcheck) Fastify plugin to add health route in your server that asserts custom functions.
|
|
95
96
|
- [`fastify-decorators`](https://github.com/L2jLiga/fastify-decorators) Fastify plugin that provides the set of TypeScript decorators.
|
|
96
97
|
- [`fastify-disablecache`](https://github.com/Fdawgs/fastify-disablecache) Fastify plugin to disable client-side caching, inspired by [nocache](https://github.com/helmetjs/nocache).
|
|
@@ -158,6 +159,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
|
|
|
158
159
|
- [`fastify-orientdb`](https://github.com/mahmed8003/fastify-orientdb) Fastify OrientDB connection plugin, with which you can share the OrientDB connection across every part of your server.
|
|
159
160
|
- [`fastify-piscina`](https://github.com/piscinajs/fastify-piscina) A worker thread pool plugin using [Piscina](https://github.com/piscinajs/piscina).
|
|
160
161
|
- [`fastify-peekaboo`](https://github.com/simone-sanfratello/fastify-peekaboo) Fastify plugin for memoize responses by expressive settings.
|
|
162
|
+
- [`fastify-polyglot`](https://github.com/heply/fastify-polyglot) A plugin to handle i18n using [node-polyglot](https://www.npmjs.com/package/node-polyglot).
|
|
161
163
|
- [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile) Plugin to integrate [PostGraphile](https://www.graphile.org/postgraphile/) in a Fastify project.
|
|
162
164
|
- [`fastify-prettier`](https://github.com/hsynlms/fastify-prettier) A Fastify plugin that uses [prettier](https://github.com/prettier/prettier) under the hood to beautify outgoing responses and/or other things in the Fastify server.
|
|
163
165
|
- [`fastify-print-routes`](https://github.com/ShogunPanda/fastify-print-routes) A Fastify plugin that prints all available routes.
|
package/docs/Getting-Started.md
CHANGED
|
@@ -262,6 +262,24 @@ async function routes (fastify, options) {
|
|
|
262
262
|
}
|
|
263
263
|
return result
|
|
264
264
|
})
|
|
265
|
+
|
|
266
|
+
const animalBodyJsonSchema = {
|
|
267
|
+
type: 'object',
|
|
268
|
+
required: ['animal'],
|
|
269
|
+
properties: {
|
|
270
|
+
animal: { type: 'string' },
|
|
271
|
+
},
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const schema = {
|
|
275
|
+
body: animalBodyJsonSchema,
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
fastify.post('/animals', { schema }, async (request, reply) => {
|
|
279
|
+
// we can use the `request.body` object to get the data sent by the client
|
|
280
|
+
const result = await collection.insertOne({ animal: request.body.animal })
|
|
281
|
+
return result
|
|
282
|
+
})
|
|
265
283
|
}
|
|
266
284
|
|
|
267
285
|
module.exports = routes
|
package/docs/Logging.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Logging
|
|
4
4
|
|
|
5
|
+
### Enable logging
|
|
5
6
|
Logging is disabled by default, and you can enable it by passing
|
|
6
7
|
`{ logger: true }` or `{ logger: { level: 'info' } }` when you create
|
|
7
8
|
a fastify instance. Note that if the logger is disabled, it is impossible to
|
|
@@ -11,13 +12,34 @@ this purpose.
|
|
|
11
12
|
|
|
12
13
|
As Fastify is focused on performance, it uses [pino](https://github.com/pinojs/pino) as its logger, with the default log level, when enabled, set to `'info'`.
|
|
13
14
|
|
|
14
|
-
Enabling the
|
|
15
|
+
Enabling the production JSON logger:
|
|
15
16
|
|
|
16
17
|
```js
|
|
17
18
|
const fastify = require('fastify')({
|
|
18
19
|
logger: true
|
|
19
20
|
})
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Enabling the logger with appropriate configuration for both local development and production environment requires bit more configuration:
|
|
24
|
+
```js
|
|
25
|
+
const fastify = require('fastify')({
|
|
26
|
+
logger: {
|
|
27
|
+
prettyPrint:
|
|
28
|
+
environment === 'development'
|
|
29
|
+
? {
|
|
30
|
+
translateTime: 'HH:MM:ss Z',
|
|
31
|
+
ignore: 'pid,hostname'
|
|
32
|
+
}
|
|
33
|
+
: false
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
⚠️ `pino-pretty` needs to be installed as a dev dependency, it is not included by default for performance reasons.
|
|
20
38
|
|
|
39
|
+
### Usage
|
|
40
|
+
You can use the logger like this in your route handlers:
|
|
41
|
+
|
|
42
|
+
```js
|
|
21
43
|
fastify.get('/', options, function (request, reply) {
|
|
22
44
|
request.log.info('Some info about the current request')
|
|
23
45
|
reply.send({ hello: 'world' })
|
package/docs/Plugins.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Fastify allows the user to extend its functionalities with plugins.
|
|
5
5
|
A plugin can be a set of routes, a server [decorator](Decorators.md), or whatever. The API that you will need to use one or more plugins, is `register`.<br>
|
|
6
6
|
|
|
7
|
-
By default, `register` creates a *new scope*, this means that if you make some changes to the Fastify instance (via `decorate`), this change will not be reflected by the current context ancestors, but only to its
|
|
7
|
+
By default, `register` creates a *new scope*, this means that if you make some changes to the Fastify instance (via `decorate`), this change will not be reflected by the current context ancestors, but only to its descendants. This feature allows us to achieve plugin *encapsulation* and *inheritance*, in this way we create a *direct acyclic graph* (DAG) and we will not have issues caused by cross dependencies.
|
|
8
8
|
|
|
9
9
|
You already see in the [getting started](Getting-Started.md#register) section how using this API is pretty straightforward.
|
|
10
10
|
```
|
package/docs/Reply.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
- [.statusCode](#statusCode)
|
|
8
8
|
- [.server](#server)
|
|
9
9
|
- [.header(key, value)](#headerkey-value)
|
|
10
|
+
- [set-cookie](#set-cookie)
|
|
10
11
|
- [.headers(object)](#headersobject)
|
|
11
12
|
- [.getHeader(key)](#getheaderkey)
|
|
12
13
|
- [.getHeaders()](#getheaders)
|
|
@@ -106,11 +107,23 @@ fastify.get('/', async function (req, rep) {
|
|
|
106
107
|
|
|
107
108
|
<a name="header"></a>
|
|
108
109
|
### .header(key, value)
|
|
109
|
-
Sets a response header. If the value is omitted or undefined, it is coerced
|
|
110
|
-
to `''`.
|
|
111
|
-
|
|
110
|
+
Sets a response header. If the value is omitted or undefined, it is coerced to `''`.
|
|
112
111
|
For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_response_setheader_name_value).
|
|
113
112
|
|
|
113
|
+
<a name="set-cookie"></a>
|
|
114
|
+
- ### set-cookie
|
|
115
|
+
- When sending different values as a cookie with `set-cookie` as the key, every value will be sent as a cookie instead of replacing the previous value.
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
reply.header('set-cookie', 'foo');
|
|
119
|
+
reply.header('set-cookie', 'bar');
|
|
120
|
+
```
|
|
121
|
+
- The browser will only consider the latest reference of a key for the `set-cookie` header. This is done to avoid parsing the `set-cookie` header when added to a reply and speeds up the serialization of the reply.
|
|
122
|
+
|
|
123
|
+
- To reset the `set-cookie` header, you need to make an explicit call to `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)` [here](#removeheaderkey).
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
114
127
|
<a name="headers"></a>
|
|
115
128
|
### .headers(object)
|
|
116
129
|
Sets all the keys of the object as response headers. [`.header`](#headerkey-value) will be called under the hood.
|
package/docs/Serverless.md
CHANGED
|
@@ -22,6 +22,7 @@ choice with an additional snippet of code.
|
|
|
22
22
|
### Contents
|
|
23
23
|
|
|
24
24
|
- [AWS Lambda](#aws-lambda)
|
|
25
|
+
- [Google Cloud Functions](#google-cloud-functions)
|
|
25
26
|
- [Google Cloud Run](#google-cloud-run)
|
|
26
27
|
- [Netlify Lambda](#netlify-lambda)
|
|
27
28
|
- [Vercel](#vercel)
|
|
@@ -100,6 +101,128 @@ An example deployable with [claudia.js](https://claudiajs.com/tutorials/serverle
|
|
|
100
101
|
- API Gateway does not support streams yet, so you are not able to handle [streams](https://www.fastify.io/docs/latest/Reply/#streams).
|
|
101
102
|
- API Gateway has a timeout of 29 seconds, so it is important to provide a reply during this time.
|
|
102
103
|
|
|
104
|
+
## Google Cloud Functions
|
|
105
|
+
|
|
106
|
+
### Creation of Fastify instance
|
|
107
|
+
```js
|
|
108
|
+
const fastify = require("fastify")({
|
|
109
|
+
logger: true // you can also define the level passing an object configuration to logger: {level: 'debug'}
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Add Custom `contentTypeParser` to Fastify instance
|
|
114
|
+
|
|
115
|
+
As explained [in issue #946](https://github.com/fastify/fastify/issues/946#issuecomment-766319521), since the Google Cloud Functions platform parses the body of the request before it arrives into Fastify instance, troubling the body request in case of `POST` and `PATCH` methods, you need to add a custom [`ContentTypeParser`](https://www.fastify.io/docs/latest/ContentTypeParser/) to mitigate this behavior.
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
fastify.addContentTypeParser('application/json', {}, (req, body, done) => {
|
|
119
|
+
done(null, body.body);
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Define your endpoint (examples)
|
|
124
|
+
|
|
125
|
+
A simple `GET` endpoint:
|
|
126
|
+
```js
|
|
127
|
+
fastify.get('/', async (request, reply) => {
|
|
128
|
+
reply.send({message: 'Hello World!'})
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Or a more complete `POST` endpoint with schema validation:
|
|
133
|
+
```js
|
|
134
|
+
fastify.route({
|
|
135
|
+
method: 'POST',
|
|
136
|
+
url: '/hello',
|
|
137
|
+
schema: {
|
|
138
|
+
body: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
name: { type: 'string'}
|
|
142
|
+
},
|
|
143
|
+
required: ['name']
|
|
144
|
+
},
|
|
145
|
+
response: {
|
|
146
|
+
200: {
|
|
147
|
+
type: 'object',
|
|
148
|
+
properties: {
|
|
149
|
+
message: {type: 'string'}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
handler: async (request, reply) => {
|
|
155
|
+
const { name } = request.body;
|
|
156
|
+
reply.code(200).send({
|
|
157
|
+
message: `Hello ${name}!`
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Implement and export the function
|
|
164
|
+
|
|
165
|
+
Final step, implement the function to handle the request and pass it to Fastify by emitting `request` event to `fastify.server`:
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
const fastifyFunction = async (request, reply) => {
|
|
169
|
+
await fastify.ready();
|
|
170
|
+
fastify.server.emit('request', request, reply)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export.fastifyFunction = fastifyFunction;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Local test
|
|
177
|
+
|
|
178
|
+
Install [Google Functions Framework for Node.js](https://github.com/GoogleCloudPlatform/functions-framework-nodejs).
|
|
179
|
+
|
|
180
|
+
You can install it globally:
|
|
181
|
+
```bash
|
|
182
|
+
npm i -g @google-cloud/functions-framework
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Or as a development library:
|
|
186
|
+
```bash
|
|
187
|
+
npm i --save-dev @google-cloud/functions-framework
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Than you can run your function locally with Functions Framework:
|
|
191
|
+
``` bash
|
|
192
|
+
npx @google-cloud/functions-framework --target=fastifyFunction
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Or add this command to your `package.json` scripts:
|
|
196
|
+
```json
|
|
197
|
+
"scripts": {
|
|
198
|
+
...
|
|
199
|
+
"dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
|
|
200
|
+
...
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
and run it with `npm run dev`.
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
### Deploy
|
|
207
|
+
```bash
|
|
208
|
+
gcloud functions deploy fastifyFunction \
|
|
209
|
+
--runtime nodejs14 --trigger-http --region $GOOGLE_REGION --allow-unauthenticated
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Read logs
|
|
213
|
+
```bash
|
|
214
|
+
gcloud functions logs read
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Example request to `/hello` endpoint
|
|
218
|
+
```bash
|
|
219
|
+
curl -X POST https://$GOOGLE_REGION-$GOOGLE_PROJECT.cloudfunctions.net/me -H "Content-Type: application/json" -d '{ "name": "Fastify" }'
|
|
220
|
+
{"message":"Hello Fastify!"}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### References
|
|
224
|
+
- [Google Cloud Functions - Node.js Quickstart ](https://cloud.google.com/functions/docs/quickstart-nodejs)
|
|
225
|
+
|
|
103
226
|
## Google Cloud Run
|
|
104
227
|
|
|
105
228
|
Unlike AWS Lambda or Google Cloud Functions, Google Cloud Run is a serverless **container** environment. Its primary purpose is to provide an infrastructure-abstracted environment to run arbitrary containers. As a result, Fastify can be deployed to Google Cloud Run with little-to-no code changes from the way you would write your Fastify app normally.
|
|
@@ -549,7 +549,7 @@ fastify.post('/the/url', { schema }, handler)
|
|
|
549
549
|
<a name="schema-serializer"></a>
|
|
550
550
|
#### Serializer Compiler
|
|
551
551
|
|
|
552
|
-
The `serializerCompiler` is a function that returns a function that must return a string from an input object.
|
|
552
|
+
The `serializerCompiler` is a function that returns a function that must return a string from an input object. When you define a response JSON Schema, you can change the default serialization method by providing a function to serialize every route where you do.
|
|
553
553
|
|
|
554
554
|
```js
|
|
555
555
|
fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '3.24.
|
|
3
|
+
const VERSION = '3.24.1'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
@@ -631,8 +631,7 @@ function fastify (options) {
|
|
|
631
631
|
function setSchemaController (schemaControllerOpts) {
|
|
632
632
|
throwIfAlreadyStarted('Cannot call "setSchemaController" when fastify instance is already started!')
|
|
633
633
|
const old = this[kSchemaController]
|
|
634
|
-
const
|
|
635
|
-
const schemaController = SchemaController.buildSchemaController(parent, Object.assign({}, old.opts, schemaControllerOpts))
|
|
634
|
+
const schemaController = SchemaController.buildSchemaController(old, Object.assign({}, old.opts, schemaControllerOpts))
|
|
636
635
|
this[kSchemaController] = schemaController
|
|
637
636
|
this.getSchema = schemaController.getSchema.bind(schemaController)
|
|
638
637
|
this.getSchemas = schemaController.getSchemas.bind(schemaController)
|
package/lib/logger.js
CHANGED
|
@@ -50,7 +50,7 @@ const serializers = {
|
|
|
50
50
|
return {
|
|
51
51
|
method: req.method,
|
|
52
52
|
url: req.url,
|
|
53
|
-
version: req.headers['accept-version'],
|
|
53
|
+
version: req.headers && req.headers['accept-version'],
|
|
54
54
|
hostname: req.hostname,
|
|
55
55
|
remoteAddress: req.ip,
|
|
56
56
|
remotePort: req.socket ? req.socket.remotePort : undefined
|
package/lib/server.js
CHANGED
|
@@ -14,19 +14,20 @@ function createServer (options, httpHandler) {
|
|
|
14
14
|
let server = null
|
|
15
15
|
if (options.serverFactory) {
|
|
16
16
|
server = options.serverFactory(httpHandler, options)
|
|
17
|
-
} else if (options.
|
|
18
|
-
if (options.
|
|
17
|
+
} else if (options.http2) {
|
|
18
|
+
if (options.https) {
|
|
19
19
|
server = http2().createSecureServer(options.https, httpHandler)
|
|
20
|
-
server.on('session', sessionTimeout(options.http2SessionTimeout))
|
|
21
20
|
} else {
|
|
22
|
-
server =
|
|
23
|
-
server.keepAliveTimeout = options.keepAliveTimeout
|
|
21
|
+
server = http2().createServer(httpHandler)
|
|
24
22
|
}
|
|
25
|
-
} else if (options.http2) {
|
|
26
|
-
server = http2().createServer(httpHandler)
|
|
27
23
|
server.on('session', sessionTimeout(options.http2SessionTimeout))
|
|
28
24
|
} else {
|
|
29
|
-
|
|
25
|
+
// this is http1
|
|
26
|
+
if (options.https) {
|
|
27
|
+
server = https.createServer(options.https, httpHandler)
|
|
28
|
+
} else {
|
|
29
|
+
server = http.createServer(httpHandler)
|
|
30
|
+
}
|
|
30
31
|
server.keepAliveTimeout = options.keepAliveTimeout
|
|
31
32
|
server.requestTimeout = options.requestTimeout
|
|
32
33
|
// we treat zero as null
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.1",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"tap": "^15.0.5",
|
|
167
167
|
"tap-mocha-reporter": "^5.0.1",
|
|
168
168
|
"then-sleep": "^1.0.1",
|
|
169
|
-
"tsd": "^0.
|
|
169
|
+
"tsd": "^0.19.0",
|
|
170
170
|
"typescript": "^4.0.2",
|
|
171
171
|
"undici": "^3.3.5",
|
|
172
172
|
"x-xss-protection": "^2.0.0",
|
package/test/logger.test.js
CHANGED
|
@@ -1516,3 +1516,19 @@ test('should create a default logger if provided one is invalid', t => {
|
|
|
1516
1516
|
|
|
1517
1517
|
t.pass()
|
|
1518
1518
|
})
|
|
1519
|
+
|
|
1520
|
+
test('should not throw error when serializing custom req', t => {
|
|
1521
|
+
t.plan(1)
|
|
1522
|
+
|
|
1523
|
+
const lines = []
|
|
1524
|
+
const dest = new stream.Writable({
|
|
1525
|
+
write: function (chunk, enc, cb) {
|
|
1526
|
+
lines.push(JSON.parse(chunk))
|
|
1527
|
+
cb()
|
|
1528
|
+
}
|
|
1529
|
+
})
|
|
1530
|
+
const fastify = Fastify({ logger: { level: 'info', stream: dest } })
|
|
1531
|
+
fastify.log.info({ req: {} })
|
|
1532
|
+
|
|
1533
|
+
t.same(lines[0].req, {})
|
|
1534
|
+
})
|
|
@@ -102,3 +102,13 @@ test('maxRequestsPerSocket should 0', async (t) => {
|
|
|
102
102
|
const initialConfig = Fastify().initialConfig
|
|
103
103
|
t.same(initialConfig.maxRequestsPerSocket, 0)
|
|
104
104
|
})
|
|
105
|
+
|
|
106
|
+
test('requestTimeout passed to server', t => {
|
|
107
|
+
t.plan(2)
|
|
108
|
+
|
|
109
|
+
const httpServer = Fastify({ maxRequestsPerSocket: 5 }).server
|
|
110
|
+
t.equal(httpServer.maxRequestsPerSocket, 5)
|
|
111
|
+
|
|
112
|
+
const httpsServer = Fastify({ maxRequestsPerSocket: 5, https: true }).server
|
|
113
|
+
t.equal(httpsServer.maxRequestsPerSocket, 5)
|
|
114
|
+
})
|
|
@@ -5,7 +5,7 @@ const { test } = require('tap')
|
|
|
5
5
|
const Fastify = require('../fastify')
|
|
6
6
|
|
|
7
7
|
test('requestTimeout passed to server', t => {
|
|
8
|
-
t.plan(
|
|
8
|
+
t.plan(5)
|
|
9
9
|
|
|
10
10
|
try {
|
|
11
11
|
Fastify({ requestTimeout: 500.1 })
|
|
@@ -24,6 +24,9 @@ test('requestTimeout passed to server', t => {
|
|
|
24
24
|
const httpServer = Fastify({ requestTimeout: 1000 }).server
|
|
25
25
|
t.equal(httpServer.requestTimeout, 1000)
|
|
26
26
|
|
|
27
|
+
const httpsServer = Fastify({ requestTimeout: 1000, https: true }).server
|
|
28
|
+
t.equal(httpsServer.requestTimeout, 1000)
|
|
29
|
+
|
|
27
30
|
const serverFactory = (handler, _) => {
|
|
28
31
|
const server = http.createServer((req, res) => {
|
|
29
32
|
handler(req, res)
|
|
@@ -1604,3 +1604,149 @@ test('setSchemaController: Inherits buildValidator from parent if not present wi
|
|
|
1604
1604
|
t.equal(childSerializerCalled, 1, 'Should be called from the child')
|
|
1605
1605
|
t.equal(res.statusCode, 400, 'Should not coearce the string into array')
|
|
1606
1606
|
})
|
|
1607
|
+
|
|
1608
|
+
test('Should throw if not default validator passed', async t => {
|
|
1609
|
+
t.plan(4)
|
|
1610
|
+
const customAjv = new Ajv({ coerceTypes: false })
|
|
1611
|
+
const someSchema = {
|
|
1612
|
+
$id: 'some',
|
|
1613
|
+
type: 'array',
|
|
1614
|
+
items: {
|
|
1615
|
+
type: 'string'
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
const anotherSchema = {
|
|
1619
|
+
$id: 'another',
|
|
1620
|
+
type: 'integer'
|
|
1621
|
+
}
|
|
1622
|
+
const plugin = fp(function (pluginInstance, _, pluginDone) {
|
|
1623
|
+
pluginInstance.setSchemaController({
|
|
1624
|
+
compilersFactory: {
|
|
1625
|
+
buildValidator: function (externalSchemas) {
|
|
1626
|
+
const schemaKeys = Object.keys(externalSchemas)
|
|
1627
|
+
t.equal(schemaKeys.length, 2)
|
|
1628
|
+
t.same(schemaKeys, ['some', 'another'])
|
|
1629
|
+
|
|
1630
|
+
for (const key of schemaKeys) {
|
|
1631
|
+
if (customAjv.getSchema(key) == null) {
|
|
1632
|
+
customAjv.addSchema(externalSchemas[key], key)
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return function validatorCompiler ({ schema }) {
|
|
1636
|
+
return customAjv.compile(schema)
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
})
|
|
1641
|
+
|
|
1642
|
+
pluginDone()
|
|
1643
|
+
})
|
|
1644
|
+
const server = Fastify()
|
|
1645
|
+
|
|
1646
|
+
server.addSchema(someSchema)
|
|
1647
|
+
|
|
1648
|
+
server.register((instance, opts, done) => {
|
|
1649
|
+
instance.addSchema(anotherSchema)
|
|
1650
|
+
|
|
1651
|
+
instance.register(plugin, {})
|
|
1652
|
+
|
|
1653
|
+
instance.post(
|
|
1654
|
+
'/',
|
|
1655
|
+
{
|
|
1656
|
+
schema: {
|
|
1657
|
+
query: {
|
|
1658
|
+
msg: {
|
|
1659
|
+
$ref: 'some#'
|
|
1660
|
+
}
|
|
1661
|
+
},
|
|
1662
|
+
headers: {
|
|
1663
|
+
'x-another': {
|
|
1664
|
+
$ref: 'another#'
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
},
|
|
1669
|
+
(req, reply) => {
|
|
1670
|
+
reply.send({ noop: 'noop' })
|
|
1671
|
+
}
|
|
1672
|
+
)
|
|
1673
|
+
|
|
1674
|
+
done()
|
|
1675
|
+
})
|
|
1676
|
+
|
|
1677
|
+
try {
|
|
1678
|
+
const res = await server.inject({
|
|
1679
|
+
method: 'POST',
|
|
1680
|
+
url: '/',
|
|
1681
|
+
query: {
|
|
1682
|
+
msg: ['string']
|
|
1683
|
+
}
|
|
1684
|
+
})
|
|
1685
|
+
|
|
1686
|
+
t.equal(res.json().message, 'querystring.msg should be array')
|
|
1687
|
+
t.equal(res.statusCode, 400, 'Should not coearce the string into array')
|
|
1688
|
+
} catch (err) {
|
|
1689
|
+
t.error(err)
|
|
1690
|
+
}
|
|
1691
|
+
})
|
|
1692
|
+
|
|
1693
|
+
test('Should throw if not default validator passed', async t => {
|
|
1694
|
+
t.plan(2)
|
|
1695
|
+
const someSchema = {
|
|
1696
|
+
$id: 'some',
|
|
1697
|
+
type: 'array',
|
|
1698
|
+
items: {
|
|
1699
|
+
type: 'string'
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
const anotherSchema = {
|
|
1703
|
+
$id: 'another',
|
|
1704
|
+
type: 'integer'
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
const server = Fastify()
|
|
1708
|
+
|
|
1709
|
+
server.addSchema(someSchema)
|
|
1710
|
+
|
|
1711
|
+
server.register((instance, opts, done) => {
|
|
1712
|
+
instance.addSchema(anotherSchema)
|
|
1713
|
+
|
|
1714
|
+
instance.post(
|
|
1715
|
+
'/',
|
|
1716
|
+
{
|
|
1717
|
+
schema: {
|
|
1718
|
+
query: {
|
|
1719
|
+
msg: {
|
|
1720
|
+
$ref: 'some#'
|
|
1721
|
+
}
|
|
1722
|
+
},
|
|
1723
|
+
headers: {
|
|
1724
|
+
'x-another': {
|
|
1725
|
+
$ref: 'another#'
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
},
|
|
1730
|
+
(req, reply) => {
|
|
1731
|
+
reply.send({ noop: 'noop' })
|
|
1732
|
+
}
|
|
1733
|
+
)
|
|
1734
|
+
|
|
1735
|
+
done()
|
|
1736
|
+
})
|
|
1737
|
+
|
|
1738
|
+
try {
|
|
1739
|
+
const res = await server.inject({
|
|
1740
|
+
method: 'POST',
|
|
1741
|
+
url: '/',
|
|
1742
|
+
query: {
|
|
1743
|
+
msg: ['string']
|
|
1744
|
+
}
|
|
1745
|
+
})
|
|
1746
|
+
|
|
1747
|
+
t.equal(res.json().message, 'querystring.msg should be array')
|
|
1748
|
+
t.equal(res.statusCode, 400, 'Should not coearce the string into array')
|
|
1749
|
+
} catch (err) {
|
|
1750
|
+
t.error(err)
|
|
1751
|
+
}
|
|
1752
|
+
})
|
|
@@ -90,6 +90,12 @@ expectAssignable<void>(server.listen('3000', '', (err, address) => {}))
|
|
|
90
90
|
expectAssignable<void>(server.listen(3000, (err, address) => {}))
|
|
91
91
|
expectAssignable<void>(server.listen('3000', (err, address) => {}))
|
|
92
92
|
|
|
93
|
+
// test listen method callback types
|
|
94
|
+
expectAssignable<void>(server.listen('3000', (err, address) => {
|
|
95
|
+
expectAssignable<Error|null>(err)
|
|
96
|
+
expectAssignable<string>(address)
|
|
97
|
+
}))
|
|
98
|
+
|
|
93
99
|
// test listen method promise
|
|
94
100
|
expectAssignable<PromiseLike<string>>(server.listen(3000))
|
|
95
101
|
expectAssignable<PromiseLike<string>>(server.listen('3000'))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expectType } from 'tsd'
|
|
2
|
-
import fastify, { RouteHandler, RawRequestDefaultExpression, RequestBodyDefault, RequestGenericInterface } from '../../fastify'
|
|
2
|
+
import fastify, { RouteHandler, RawRequestDefaultExpression, RequestBodyDefault, RequestGenericInterface, FastifyContext, ContextConfigDefault, FastifyContextConfig } from '../../fastify'
|
|
3
3
|
import { RequestParamsDefault, RequestHeadersDefault, RequestQuerystringDefault } from '../../types/utils'
|
|
4
4
|
import { FastifyLoggerInstance } from '../../types/logger'
|
|
5
5
|
import { FastifyRequest } from '../../types/request'
|
|
@@ -50,6 +50,8 @@ const getHandler: RouteHandler = function (request, _reply) {
|
|
|
50
50
|
expectType<RawRequestDefaultExpression>(request.raw)
|
|
51
51
|
expectType<RequestBodyDefault>(request.body)
|
|
52
52
|
expectType<RequestParamsDefault>(request.params)
|
|
53
|
+
expectType<FastifyContext<ContextConfigDefault>>(request.context)
|
|
54
|
+
expectType<FastifyContextConfig>(request.context.config)
|
|
53
55
|
|
|
54
56
|
expectType<RequestHeadersDefault & RawRequestDefaultExpression['headers']>(request.headers)
|
|
55
57
|
request.headers = {}
|
|
@@ -72,6 +74,8 @@ const postHandler: Handler = function (request) {
|
|
|
72
74
|
expectType<number>(request.params.id)
|
|
73
75
|
expectType<string>(request.headers['x-foobar'])
|
|
74
76
|
expectType<FastifyInstance>(request.server)
|
|
77
|
+
expectType<FastifyContext<ContextConfigDefault>>(request.context)
|
|
78
|
+
expectType<FastifyContextConfig>(request.context.config)
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
function putHandler (request: CustomRequest, reply: FastifyReply) {
|
|
@@ -84,6 +88,8 @@ function putHandler (request: CustomRequest, reply: FastifyReply) {
|
|
|
84
88
|
expectType<number>(request.params.id)
|
|
85
89
|
expectType<string>(request.headers['x-foobar'])
|
|
86
90
|
expectType<FastifyInstance>(request.server)
|
|
91
|
+
expectType<FastifyContext<ContextConfigDefault>>(request.context)
|
|
92
|
+
expectType<FastifyContextConfig>(request.context.config)
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
const server = fastify()
|
|
@@ -65,6 +65,9 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
65
65
|
expectType<QuerystringInterface>(req.query)
|
|
66
66
|
expectType<ParamsInterface>(req.params)
|
|
67
67
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
68
|
+
expectType<string>(req.context.config.foo)
|
|
69
|
+
expectType<number>(req.context.config.bar)
|
|
70
|
+
expectType<boolean>(req.context.config.extra)
|
|
68
71
|
expectType<string>(res.context.config.foo)
|
|
69
72
|
expectType<number>(res.context.config.bar)
|
|
70
73
|
expectType<boolean>(res.context.config.extra)
|
|
@@ -80,6 +83,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
80
83
|
expectType<QuerystringInterface>(req.query)
|
|
81
84
|
expectType<ParamsInterface>(req.params)
|
|
82
85
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
86
|
+
expectType<string>(req.context.config.foo)
|
|
87
|
+
expectType<number>(req.context.config.bar)
|
|
83
88
|
expectType<string>(res.context.config.foo)
|
|
84
89
|
expectType<number>(res.context.config.bar)
|
|
85
90
|
},
|
|
@@ -88,6 +93,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
88
93
|
expectType<QuerystringInterface>(req.query)
|
|
89
94
|
expectType<ParamsInterface>(req.params)
|
|
90
95
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
96
|
+
expectType<string>(req.context.config.foo)
|
|
97
|
+
expectType<number>(req.context.config.bar)
|
|
91
98
|
expectType<string>(res.context.config.foo)
|
|
92
99
|
expectType<number>(res.context.config.bar)
|
|
93
100
|
expectType<RequestPayload>(payload)
|
|
@@ -99,6 +106,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
99
106
|
expectType<QuerystringInterface>(req.query)
|
|
100
107
|
expectType<ParamsInterface>(req.params)
|
|
101
108
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
109
|
+
expectType<string>(req.context.config.foo)
|
|
110
|
+
expectType<number>(req.context.config.bar)
|
|
102
111
|
expectType<string>(res.context.config.foo)
|
|
103
112
|
expectType<number>(res.context.config.bar)
|
|
104
113
|
},
|
|
@@ -107,6 +116,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
107
116
|
expectType<QuerystringInterface>(req.query)
|
|
108
117
|
expectType<ParamsInterface>(req.params)
|
|
109
118
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
119
|
+
expectType<string>(req.context.config.foo)
|
|
120
|
+
expectType<number>(req.context.config.bar)
|
|
110
121
|
expectType<string>(res.context.config.foo)
|
|
111
122
|
expectType<number>(res.context.config.bar)
|
|
112
123
|
},
|
|
@@ -115,6 +126,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
115
126
|
expectType<QuerystringInterface>(req.query)
|
|
116
127
|
expectType<ParamsInterface>(req.params)
|
|
117
128
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
129
|
+
expectType<string>(req.context.config.foo)
|
|
130
|
+
expectType<number>(req.context.config.bar)
|
|
118
131
|
expectType<string>(res.context.config.foo)
|
|
119
132
|
expectType<number>(res.context.config.bar)
|
|
120
133
|
expectType<number>(res.statusCode)
|
|
@@ -124,6 +137,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
124
137
|
expectType<QuerystringInterface>(req.query)
|
|
125
138
|
expectType<ParamsInterface>(req.params)
|
|
126
139
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
140
|
+
expectType<string>(req.context.config.foo)
|
|
141
|
+
expectType<number>(req.context.config.bar)
|
|
127
142
|
expectType<string>(res.context.config.foo)
|
|
128
143
|
expectType<number>(res.context.config.bar)
|
|
129
144
|
},
|
|
@@ -132,6 +147,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
132
147
|
expectType<QuerystringInterface>(req.query)
|
|
133
148
|
expectType<ParamsInterface>(req.params)
|
|
134
149
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
150
|
+
expectType<string>(req.context.config.foo)
|
|
151
|
+
expectType<number>(req.context.config.bar)
|
|
135
152
|
expectType<string>(res.context.config.foo)
|
|
136
153
|
expectType<number>(res.context.config.bar)
|
|
137
154
|
},
|
|
@@ -140,6 +157,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
140
157
|
expectType<QuerystringInterface>(req.query)
|
|
141
158
|
expectType<ParamsInterface>(req.params)
|
|
142
159
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
160
|
+
expectType<string>(req.context.config.foo)
|
|
161
|
+
expectType<number>(req.context.config.bar)
|
|
143
162
|
expectType<string>(res.context.config.foo)
|
|
144
163
|
expectType<number>(res.context.config.bar)
|
|
145
164
|
},
|
|
@@ -148,6 +167,8 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
|
|
|
148
167
|
expectType<QuerystringInterface>(req.query)
|
|
149
168
|
expectType<ParamsInterface>(req.params)
|
|
150
169
|
expectType<http.IncomingHttpHeaders & HeadersInterface>(req.headers)
|
|
170
|
+
expectType<string>(req.context.config.foo)
|
|
171
|
+
expectType<number>(req.context.config.bar)
|
|
151
172
|
expectType<string>(res.context.config.foo)
|
|
152
173
|
expectType<number>(res.context.config.bar)
|
|
153
174
|
}
|
package/types/instance.d.ts
CHANGED
|
@@ -70,11 +70,11 @@ export interface FastifyInstance<
|
|
|
70
70
|
inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
|
|
71
71
|
inject(): LightMyRequestChain;
|
|
72
72
|
|
|
73
|
-
listen(port: number | string, address: string, backlog: number, callback: (err: Error, address: string) => void): void;
|
|
74
|
-
listen(port: number | string, address: string, callback: (err: Error, address: string) => void): void;
|
|
75
|
-
listen(port: number | string, callback: (err: Error, address: string) => void): void;
|
|
73
|
+
listen(port: number | string, address: string, backlog: number, callback: (err: Error|null, address: string) => void): void;
|
|
74
|
+
listen(port: number | string, address: string, callback: (err: Error|null, address: string) => void): void;
|
|
75
|
+
listen(port: number | string, callback: (err: Error|null, address: string) => void): void;
|
|
76
76
|
listen(port: number | string, address?: string, backlog?: number): Promise<string>;
|
|
77
|
-
listen(opts: { port: number; host?: string; backlog?: number }, callback: (err: Error, address: string) => void): void;
|
|
77
|
+
listen(opts: { port: number; host?: string; backlog?: number }, callback: (err: Error|null, address: string) => void): void;
|
|
78
78
|
listen(opts: { port: number; host?: string; backlog?: number }): Promise<string>;
|
|
79
79
|
|
|
80
80
|
ready(): FastifyInstance<RawServer, RawRequest, RawReply> & PromiseLike<undefined>;
|
package/types/request.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { FastifyLoggerInstance } from './logger'
|
|
2
|
-
import { RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './utils'
|
|
2
|
+
import { ContextConfigDefault, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './utils'
|
|
3
3
|
import { RouteGenericInterface } from './route'
|
|
4
4
|
import { FastifyInstance } from './instance'
|
|
5
|
+
import { FastifyContext } from './context'
|
|
5
6
|
|
|
6
7
|
export interface RequestGenericInterface {
|
|
7
8
|
Body?: RequestBodyDefault;
|
|
@@ -18,6 +19,7 @@ export interface FastifyRequest<
|
|
|
18
19
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
|
19
20
|
RawServer extends RawServerBase = RawServerDefault,
|
|
20
21
|
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
|
|
22
|
+
ContextConfig = ContextConfigDefault,
|
|
21
23
|
> {
|
|
22
24
|
id: any;
|
|
23
25
|
params: RouteGeneric['Params'];
|
|
@@ -27,6 +29,7 @@ export interface FastifyRequest<
|
|
|
27
29
|
log: FastifyLoggerInstance;
|
|
28
30
|
server: FastifyInstance;
|
|
29
31
|
body: RouteGeneric['Body'];
|
|
32
|
+
context: FastifyContext<ContextConfig>;
|
|
30
33
|
|
|
31
34
|
/** in order for this to be used the user should ensure they have set the attachValidation option. */
|
|
32
35
|
validationError?: Error & { validation: any; validationContext: string };
|
package/types/route.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type RouteHandlerMethod<
|
|
|
59
59
|
ContextConfig = ContextConfigDefault
|
|
60
60
|
> = (
|
|
61
61
|
this: FastifyInstance<RawServer, RawRequest, RawReply>,
|
|
62
|
-
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
62
|
+
request: FastifyRequest<RouteGeneric, RawServer, RawRequest, ContextConfig>,
|
|
63
63
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
|
|
64
64
|
) => void | Promise<RouteGeneric['Reply'] | void>
|
|
65
65
|
|