fastify 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -14
- package/docs/Guides/Database.md +2 -2
- package/docs/Guides/Delay-Accepting-Requests.md +1 -1
- package/docs/Guides/Ecosystem.md +31 -16
- package/docs/Guides/Migration-Guide-V4.md +69 -1
- package/docs/Guides/Plugins-Guide.md +5 -0
- package/docs/Guides/Serverless.md +23 -10
- package/docs/Reference/HTTP2.md +1 -3
- package/docs/Reference/Hooks.md +52 -0
- package/docs/Reference/Plugins.md +1 -1
- package/docs/Reference/Reply.md +176 -0
- package/docs/Reference/Request.md +171 -0
- package/docs/Reference/Type-Providers.md +1 -15
- package/docs/Reference/TypeScript.md +65 -28
- package/docs/Reference/Validation-and-Serialization.md +11 -0
- package/docs/index.md +1 -1
- package/fastify.d.ts +3 -3
- package/fastify.js +2 -2
- package/integration/server.js +27 -0
- package/integration/test.sh +23 -0
- package/lib/contentTypeParser.js +10 -2
- package/lib/context.js +14 -2
- package/lib/error-serializer.js +24 -27
- package/lib/errors.js +8 -0
- package/lib/handleRequest.js +1 -1
- package/lib/reply.js +101 -24
- package/lib/request.js +97 -1
- package/lib/route.js +41 -29
- package/lib/symbols.js +17 -10
- package/lib/validation.js +2 -0
- package/package.json +9 -9
- package/test/build/error-serializer.test.js +3 -1
- package/test/content-parser.test.js +15 -0
- package/test/hooks.test.js +21 -0
- package/test/internals/reply-serialize.test.js +583 -0
- package/test/internals/request-validate.test.js +1269 -0
- package/test/internals/request.test.js +11 -2
- package/test/pretty-print.test.js +3 -3
- package/test/reply-error.test.js +1 -1
- package/test/request-error.test.js +44 -1
- package/test/schema-feature.test.js +2 -2
- package/test/schema-validation.test.js +71 -0
- package/test/types/fastify.test-d.ts +24 -2
- package/test/types/hooks.test-d.ts +1 -2
- package/test/types/import.ts +1 -1
- package/test/types/instance.test-d.ts +4 -1
- package/test/types/request.test-d.ts +8 -4
- package/test/types/type-provider.test-d.ts +87 -8
- package/test/validation-error-handling.test.js +38 -1
- package/types/hooks.d.ts +19 -39
- package/types/instance.d.ts +78 -130
- package/types/reply.d.ts +5 -0
- package/types/request.d.ts +16 -3
- package/types/route.d.ts +25 -33
- package/types/schema.d.ts +4 -1
- package/types/type-provider.d.ts +19 -11
|
@@ -35,6 +35,19 @@ Request is a core Fastify object containing the following fields:
|
|
|
35
35
|
- `connection` - Deprecated, use `socket` instead. The underlying connection of
|
|
36
36
|
the incoming request.
|
|
37
37
|
- `socket` - the underlying connection of the incoming request
|
|
38
|
+
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
|
|
39
|
+
Returns a validation function for the specified schema or http part,
|
|
40
|
+
if any of either are set or cached.
|
|
41
|
+
- [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
|
|
42
|
+
Compiles the specified schema and returns a validation function
|
|
43
|
+
using the default (or customized) `ValidationCompiler`.
|
|
44
|
+
The optional `httpPart` is forwarded to the `ValidationCompiler`
|
|
45
|
+
if provided, defaults to `null`.
|
|
46
|
+
- [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
|
|
47
|
+
Validates the specified input by using the specified
|
|
48
|
+
schema and returns the serialized payload. If the optional
|
|
49
|
+
`httpPart` is provided, the function will use the serializer
|
|
50
|
+
function given for that HTTP Status Code. Defaults to `null`.
|
|
38
51
|
- `context` - A Fastify internal object. You should not use it directly or
|
|
39
52
|
modify it. It is useful to access one special key:
|
|
40
53
|
- `context.config` - The route [`config`](./Routes.md#routes-config) object.
|
|
@@ -77,3 +90,161 @@ fastify.post('/:params', options, function (request, reply) {
|
|
|
77
90
|
request.log.info('some info')
|
|
78
91
|
})
|
|
79
92
|
```
|
|
93
|
+
### .getValidationFunction(schema | httpPart)
|
|
94
|
+
<a id="getvalidationfunction"></a>
|
|
95
|
+
|
|
96
|
+
By calling this function using a provided `schema` or `httpPart`,
|
|
97
|
+
it will return a `validation` function that can be used to
|
|
98
|
+
validate diverse inputs. It returns `undefined` if no
|
|
99
|
+
serialization function was found using either of the provided inputs.
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const validate = request
|
|
103
|
+
.getValidationFunction({
|
|
104
|
+
type: 'object',
|
|
105
|
+
properties: {
|
|
106
|
+
foo: {
|
|
107
|
+
type: 'string'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
validate({ foo: 'bar' }) // true
|
|
112
|
+
|
|
113
|
+
// or
|
|
114
|
+
|
|
115
|
+
const validate = request
|
|
116
|
+
.getValidationFunction('body')
|
|
117
|
+
validate({ foo: 0.5 }) // false
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
See [.compilaValidationSchema(schema, [httpStatus])](#compilevalidationschema)
|
|
121
|
+
for more information on how to compile validation function.
|
|
122
|
+
|
|
123
|
+
### .compileValidationSchema(schema, [httpPart])
|
|
124
|
+
<a id="compilevalidationschema"></a>
|
|
125
|
+
|
|
126
|
+
This function will compile a validation schema and
|
|
127
|
+
return a function that can be used to validate data.
|
|
128
|
+
The function returned (a.k.a. _validation function_) is compiled
|
|
129
|
+
by using the provided [`SchemaControler#ValidationCompiler`](./Server.md#schema-controller).
|
|
130
|
+
A `WeakMap` is used to cached this, reducing compilation calls.
|
|
131
|
+
|
|
132
|
+
The optional parameter `httpPart`, if provided, is forwarded directly
|
|
133
|
+
the `ValidationCompiler`, so it can be used to compile the validation
|
|
134
|
+
function if a custom `ValidationCompiler` is provided for the route.
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const validate = request
|
|
139
|
+
.compileValidationSchema({
|
|
140
|
+
type: 'object',
|
|
141
|
+
properties: {
|
|
142
|
+
foo: {
|
|
143
|
+
type: 'string'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
console.log(validate({ foo: 'bar' })) // true
|
|
148
|
+
|
|
149
|
+
// or
|
|
150
|
+
|
|
151
|
+
const validate = request
|
|
152
|
+
.compileValidationSchema({
|
|
153
|
+
type: 'object',
|
|
154
|
+
properties: {
|
|
155
|
+
foo: {
|
|
156
|
+
type: 'string'
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}, 200)
|
|
160
|
+
console.log(validate({ hello: 'world' })) // false
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Note that you should be careful when using this function, as it will cache
|
|
164
|
+
the compiled validation functions based on the schema provided. If the
|
|
165
|
+
schemas provided are mutated or changed, the validation functions will not
|
|
166
|
+
detect that the schema has been altered and for instance it will reuse the
|
|
167
|
+
previously compiled validation function, as the cache is based on
|
|
168
|
+
the reference of the schema (Object) previously provided.
|
|
169
|
+
|
|
170
|
+
If there is a need to change the properties of a schema, always opt to create
|
|
171
|
+
a totally new schema (object), otherwise the implementation will not benefit from
|
|
172
|
+
the cache mechanism.
|
|
173
|
+
|
|
174
|
+
Using the following schema as an example:
|
|
175
|
+
```js
|
|
176
|
+
const schema1 = {
|
|
177
|
+
type: 'object',
|
|
178
|
+
properties: {
|
|
179
|
+
foo: {
|
|
180
|
+
type: 'string'
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
*Not*
|
|
187
|
+
```js
|
|
188
|
+
const validate = request.compileValidationSchema(schema1)
|
|
189
|
+
|
|
190
|
+
// Later on...
|
|
191
|
+
schema1.properties.foo.type. = 'integer'
|
|
192
|
+
const newValidate = request.compileValidationSchema(schema1)
|
|
193
|
+
|
|
194
|
+
console.log(newValidate === validate) // true
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
*Instead*
|
|
198
|
+
```js
|
|
199
|
+
const validate = request.compileValidationSchema(schema1)
|
|
200
|
+
|
|
201
|
+
// Later on...
|
|
202
|
+
const newSchema = Object.assign({}, schema1)
|
|
203
|
+
newSchema.properties.foo.type = 'integer'
|
|
204
|
+
|
|
205
|
+
const newValidate = request.compileValidationSchema(newSchema)
|
|
206
|
+
|
|
207
|
+
console.log(newValidate === validate) // false
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### .validateInput(data, [schema | httpStatus], [httpStatus])
|
|
211
|
+
<a id="validate"></a>
|
|
212
|
+
|
|
213
|
+
This function will validate the input based on the provided schema,
|
|
214
|
+
or HTTP part passed. If both are provided, the `httpPart` parameter
|
|
215
|
+
will take precedence.
|
|
216
|
+
|
|
217
|
+
If there is not a validation function for a given `schema`, a new validation
|
|
218
|
+
function will be compiled, forwarding the `httpPart` if provided.
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
request
|
|
222
|
+
.validateInput({ foo: 'bar'}, {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
foo: {
|
|
226
|
+
type: 'string'
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}) // true
|
|
230
|
+
|
|
231
|
+
// or
|
|
232
|
+
|
|
233
|
+
request
|
|
234
|
+
.validateInput({ foo: 'bar'}, {
|
|
235
|
+
type: 'object',
|
|
236
|
+
properties: {
|
|
237
|
+
foo: {
|
|
238
|
+
type: 'string'
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}, 'body') // true
|
|
242
|
+
|
|
243
|
+
// or
|
|
244
|
+
|
|
245
|
+
request
|
|
246
|
+
.validateInput({ hello: 'world'}, 'query') // false
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
|
|
250
|
+
for more information on how to compile validation schemas.
|
|
@@ -70,14 +70,7 @@ import { Type } from '@sinclair/typebox'
|
|
|
70
70
|
|
|
71
71
|
import fastify from 'fastify'
|
|
72
72
|
|
|
73
|
-
const server = fastify(
|
|
74
|
-
ajv: {
|
|
75
|
-
customOptions: {
|
|
76
|
-
strict: 'log',
|
|
77
|
-
keywords: ['kind', 'modifier'],
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
}).withTypeProvider<TypeBoxTypeProvider>()
|
|
73
|
+
const server = fastify().withTypeProvider<TypeBoxTypeProvider>()
|
|
81
74
|
|
|
82
75
|
server.get('/route', {
|
|
83
76
|
schema: {
|
|
@@ -94,13 +87,6 @@ server.get('/route', {
|
|
|
94
87
|
})
|
|
95
88
|
```
|
|
96
89
|
|
|
97
|
-
TypeBox uses the properties `kind` and `modifier` internally. These properties
|
|
98
|
-
are not strictly valid JSON schema which will cause `AJV@7` and newer versions
|
|
99
|
-
to throw an invalid schema error. To remove the error it's either necessary to
|
|
100
|
-
omit the properties by using
|
|
101
|
-
[`Type.Strict()`](https://github.com/sinclairzx81/typebox#strict) or use the AJV
|
|
102
|
-
options for adding custom keywords.
|
|
103
|
-
|
|
104
90
|
See also the [TypeBox
|
|
105
91
|
documentation](https://github.com/sinclairzx81/typebox#validation) on how to set
|
|
106
92
|
up AJV to work with TypeBox.
|
|
@@ -143,7 +143,7 @@ route-level `request` object.
|
|
|
143
143
|
curl localhost:8080/auth?username=admin&password=Password123!
|
|
144
144
|
```
|
|
145
145
|
And it should return back `logged in!`
|
|
146
|
-
6. But wait
|
|
146
|
+
6. But wait there's more! The generic interfaces are also available inside route
|
|
147
147
|
level hook methods. Modify the previous route by adding a `preValidation`
|
|
148
148
|
hook:
|
|
149
149
|
```typescript
|
|
@@ -199,17 +199,18 @@ Below is how to setup schema validation using vanilla `typebox` and
|
|
|
199
199
|
#### typebox
|
|
200
200
|
|
|
201
201
|
A useful library for building types and a schema at once is
|
|
202
|
-
[typebox](https://www.npmjs.com/package/@sinclair/typebox)
|
|
203
|
-
|
|
204
|
-
you
|
|
202
|
+
[typebox](https://www.npmjs.com/package/@sinclair/typebox) along with
|
|
203
|
+
[fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox).
|
|
204
|
+
With typebox you define your schema within your code and use them
|
|
205
|
+
directly as types or schemas as you need them.
|
|
205
206
|
|
|
206
207
|
When you want to use it for validation of some payload in a fastify route you
|
|
207
208
|
can do it as follows:
|
|
208
209
|
|
|
209
|
-
1. Install `typebox` in your project.
|
|
210
|
+
1. Install `typebox` and `fastify-type-provider-typebox` in your project.
|
|
210
211
|
|
|
211
212
|
```bash
|
|
212
|
-
npm i @sinclair/typebox
|
|
213
|
+
npm i @sinclair/typebox @fastify/type-provider-typebox
|
|
213
214
|
```
|
|
214
215
|
|
|
215
216
|
2. Define the schema you need with `Type` and create the respective type with
|
|
@@ -218,40 +219,52 @@ can do it as follows:
|
|
|
218
219
|
```typescript
|
|
219
220
|
import { Static, Type } from '@sinclair/typebox'
|
|
220
221
|
|
|
221
|
-
const User = Type.Object({
|
|
222
|
+
export const User = Type.Object({
|
|
222
223
|
name: Type.String(),
|
|
223
|
-
mail: Type.Optional(Type.String({ format:
|
|
224
|
-
})
|
|
225
|
-
|
|
224
|
+
mail: Type.Optional(Type.String({ format: 'email' })),
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
export type UserType = Static<typeof User>
|
|
226
228
|
```
|
|
227
229
|
|
|
228
230
|
3. Use the defined type and schema during the definition of your route
|
|
229
231
|
|
|
230
232
|
```typescript
|
|
231
|
-
|
|
233
|
+
import Fastify from 'fastify'
|
|
234
|
+
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
235
|
+
// ...
|
|
236
|
+
|
|
237
|
+
const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
|
|
232
238
|
|
|
233
|
-
app.post<{ Body: UserType
|
|
234
|
-
|
|
239
|
+
app.post<{ Body: UserType, Reply: UserType }>(
|
|
240
|
+
'/',
|
|
235
241
|
{
|
|
236
242
|
schema: {
|
|
237
243
|
body: User,
|
|
238
244
|
response: {
|
|
239
|
-
200: User
|
|
245
|
+
200: User
|
|
240
246
|
},
|
|
241
247
|
},
|
|
242
248
|
},
|
|
243
249
|
(request, reply) => {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
// The `name` and `mail` types are automatically inferred
|
|
251
|
+
const { name, mail } = request.body;
|
|
252
|
+
reply.status(200).send({ name, mail });
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Note** For Ajv version 7 and above is required to use the `ajvTypeBoxPlugin`:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import Fastify from 'fastify'
|
|
261
|
+
import { ajvTypeBoxPlugin, TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
262
|
+
|
|
263
|
+
const fastify = Fastify({
|
|
264
|
+
ajv: {
|
|
265
|
+
plugins: [ajvTypeBoxPlugin]
|
|
253
266
|
}
|
|
254
|
-
)
|
|
267
|
+
}).withTypeProvider<TypeBoxTypeProvider>()
|
|
255
268
|
```
|
|
256
269
|
|
|
257
270
|
#### Schemas in JSON Files
|
|
@@ -390,7 +403,7 @@ definitions.
|
|
|
390
403
|
#### json-schema-to-ts
|
|
391
404
|
|
|
392
405
|
If you do not want to generate types from your schemas, but want to use them
|
|
393
|
-
|
|
406
|
+
directly from your code, you can use the package
|
|
394
407
|
[json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts).
|
|
395
408
|
|
|
396
409
|
You can install it as dev-dependency.
|
|
@@ -648,6 +661,30 @@ However, there are a couple of suggestions to help improve this experience:
|
|
|
648
661
|
[npm-check](https://www.npmjs.com/package/npm-check) to verify plugin
|
|
649
662
|
dependencies are being used somewhere in your project.
|
|
650
663
|
|
|
664
|
+
Note that using `require` will not load the type definitions properly and may
|
|
665
|
+
cause type errors.
|
|
666
|
+
TypeScript can only identify the types that are directly imported into code,
|
|
667
|
+
which means that you can use require inline with import on top. For example:
|
|
668
|
+
|
|
669
|
+
```typescript
|
|
670
|
+
import 'plugin' // here will trigger the type augmentation.
|
|
671
|
+
|
|
672
|
+
fastify.register(require('plugin'))
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
```typescript
|
|
676
|
+
import plugin from 'plugin' // here will trigger the type augmentation.
|
|
677
|
+
|
|
678
|
+
fastify.register(plugin)
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
Or even explicit config on tsconfig
|
|
682
|
+
```jsonc
|
|
683
|
+
{
|
|
684
|
+
"types": ["plugin"] // we force TypeScript to import the types
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
651
688
|
## Code Completion In Vanilla JavaScript
|
|
652
689
|
|
|
653
690
|
Vanilla JavaScript can use the published types to provide code completion (e.g.
|
|
@@ -1359,17 +1396,17 @@ A method for checking the existence of a type parser of a certain content type
|
|
|
1359
1396
|
|
|
1360
1397
|
##### fastify.FastifyError
|
|
1361
1398
|
|
|
1362
|
-
[src](https://github.com/fastify/fastify/blob/main/
|
|
1399
|
+
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179)
|
|
1363
1400
|
|
|
1364
1401
|
FastifyError is a custom error object that includes status code and validation
|
|
1365
1402
|
results.
|
|
1366
1403
|
|
|
1367
1404
|
It extends the Node.js `Error` type, and adds two additional, optional
|
|
1368
|
-
properties: `statusCode: number` and `validation:
|
|
1405
|
+
properties: `statusCode: number` and `validation: ValidationResult[]`.
|
|
1369
1406
|
|
|
1370
1407
|
##### fastify.ValidationResult
|
|
1371
1408
|
|
|
1372
|
-
[src](https://github.com/fastify/fastify/blob/main/
|
|
1409
|
+
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184)
|
|
1373
1410
|
|
|
1374
1411
|
The route validation internally relies upon Ajv, which is a high-performance
|
|
1375
1412
|
JSON schema validator.
|
|
@@ -484,6 +484,17 @@ fastify.post('/the/url', {
|
|
|
484
484
|
}, handler)
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
+
##### .statusCode property
|
|
488
|
+
|
|
489
|
+
All validation errors will be added a `.statusCode` property set to `400`. This guarantees
|
|
490
|
+
that the default error handler will set the status code of the response to `400`.
|
|
491
|
+
|
|
492
|
+
```js
|
|
493
|
+
fastify.setErrorHandler(function (error, request, reply) {
|
|
494
|
+
request.log.error(error, `This error has status code ${error.statusCode}`)
|
|
495
|
+
reply.status(error.statusCode).send(error)
|
|
496
|
+
})
|
|
497
|
+
```
|
|
487
498
|
|
|
488
499
|
##### Validation messages with other validation libraries
|
|
489
500
|
|
package/docs/index.md
CHANGED
|
@@ -16,7 +16,7 @@ Complete newcomers to Fastify should first read our [Getting
|
|
|
16
16
|
Started](./Guides/Getting-Started.md) guide.
|
|
17
17
|
|
|
18
18
|
Developers experienced with Fastify should consult the [reference
|
|
19
|
-
documentation](./Reference/
|
|
19
|
+
documentation](./Reference/Index.md) directly to find the topic they are seeking
|
|
20
20
|
more information about.
|
|
21
21
|
|
|
22
22
|
## Additional Documentation
|
package/fastify.d.ts
CHANGED
|
@@ -183,10 +183,10 @@ declare module '@fastify/error' {
|
|
|
183
183
|
|
|
184
184
|
export interface ValidationResult {
|
|
185
185
|
keyword: string;
|
|
186
|
-
|
|
186
|
+
instancePath: string;
|
|
187
187
|
schemaPath: string;
|
|
188
188
|
params: Record<string, string | string[]>;
|
|
189
|
-
message
|
|
189
|
+
message?: string;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/* Export all additional types */
|
|
@@ -194,7 +194,7 @@ export type { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRe
|
|
|
194
194
|
export { FastifyRequest, RequestGenericInterface } from './types/request'
|
|
195
195
|
export { FastifyReply } from './types/reply'
|
|
196
196
|
export { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
|
|
197
|
-
export { FastifyInstance, PrintRoutesOptions } from './types/instance'
|
|
197
|
+
export { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
|
|
198
198
|
export { FastifyLoggerOptions, FastifyBaseLogger, FastifyLoggerInstance, FastifyLogFn, LogLevel } from './types/logger'
|
|
199
199
|
export { FastifyContext, FastifyContextConfig } from './types/context'
|
|
200
200
|
export { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '4.
|
|
3
|
+
const VERSION = '4.3.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
@@ -621,7 +621,7 @@ function fastify (options) {
|
|
|
621
621
|
// https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
|
|
622
622
|
|
|
623
623
|
// If the socket is not writable, there is no reason to try to send data.
|
|
624
|
-
if (socket.writable
|
|
624
|
+
if (socket.writable) {
|
|
625
625
|
socket.write(`HTTP/1.1 400 Bad Request\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
|
|
626
626
|
}
|
|
627
627
|
socket.destroy(err)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const Fastify = require('../fastify')
|
|
2
|
+
|
|
3
|
+
const fastify = Fastify()
|
|
4
|
+
|
|
5
|
+
fastify.listen({
|
|
6
|
+
host: '::',
|
|
7
|
+
port: 3000
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
fastify.get('/', async function (request, reply) {
|
|
11
|
+
reply.code(200).send({ data: 'home page' })
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
fastify.post('/post/:id', async function (request, reply) {
|
|
15
|
+
const { id } = request.params
|
|
16
|
+
reply.code(201).send({ data: `${id}` })
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
fastify.put('/put/:id', async function (request, reply) {
|
|
20
|
+
const { id } = request.params
|
|
21
|
+
reply.code(200).send({ data: `${id}` })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
fastify.delete('/delete/:id', async function (request, reply) {
|
|
25
|
+
const { id } = request.params
|
|
26
|
+
reply.code(204).send({ data: `${id}` })
|
|
27
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
NUMBER=$RANDOM
|
|
6
|
+
curl -i -X GET -H 'Content-Type: application/json' localhost:3000/ > GET
|
|
7
|
+
if [[ ! $(cat GET | head -1| cut -f2 -d" ") == "200" || ! $(cat GET | tail -1| cut -f4 -d"\"") == "home page" ]] ; then
|
|
8
|
+
exit 1
|
|
9
|
+
fi;
|
|
10
|
+
curl -i -X POST -H 'Content-Type: application/json' localhost:3000/post/$NUMBER --data {} > POST
|
|
11
|
+
if [[ ! $(cat POST | head -1| cut -f2 -d" ") == "201" || ! $(cat POST | tail -1| cut -f4 -d"\"") == $(echo $NUMBER) ]]; then
|
|
12
|
+
exit 1
|
|
13
|
+
fi;
|
|
14
|
+
curl -i -X PUT -H 'Content-Type: application/json' localhost:3000/put/$NUMBER --data {} > PUT
|
|
15
|
+
if [[ ! $(cat PUT | head -1| cut -f2 -d" ") == "200" || ! $(cat PUT | tail -1| cut -f4 -d"\"") == $(echo $NUMBER) ]]; then
|
|
16
|
+
exit 1
|
|
17
|
+
fi;
|
|
18
|
+
curl -i -X DELETE -H 'Content-Type: application/json' localhost:3000/delete/$NUMBER --data {} > DELETE
|
|
19
|
+
if [[ ! $(cat DELETE | head -1| cut -f2 -d" ") == "204" ]]; then
|
|
20
|
+
exit 1
|
|
21
|
+
fi;
|
|
22
|
+
|
|
23
|
+
rm -f GET POST PUT DELETE
|
package/lib/contentTypeParser.js
CHANGED
|
@@ -92,10 +92,18 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
ContentTypeParser.prototype.getParser = function (contentType) {
|
|
95
|
+
if (contentType in this.customParsers) {
|
|
96
|
+
return this.customParsers[contentType]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.cache.has(contentType)) {
|
|
100
|
+
return this.cache.get(contentType)
|
|
101
|
+
}
|
|
102
|
+
|
|
95
103
|
// eslint-disable-next-line no-var
|
|
96
104
|
for (var i = 0; i !== this.parserList.length; ++i) {
|
|
97
105
|
const parserName = this.parserList[i]
|
|
98
|
-
if (contentType.indexOf(parserName)
|
|
106
|
+
if (contentType.indexOf(parserName) !== -1) {
|
|
99
107
|
const parser = this.customParsers[parserName]
|
|
100
108
|
this.cache.set(contentType, parser)
|
|
101
109
|
return parser
|
|
@@ -137,7 +145,7 @@ ContentTypeParser.prototype.remove = function (contentType) {
|
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
|
|
140
|
-
const parser = this.
|
|
148
|
+
const parser = this.getParser(contentType)
|
|
141
149
|
const resource = new AsyncResource('content-type-parser:run', request)
|
|
142
150
|
|
|
143
151
|
if (parser === undefined) {
|
package/lib/context.js
CHANGED
|
@@ -9,7 +9,10 @@ const {
|
|
|
9
9
|
kRequest,
|
|
10
10
|
kBodyLimit,
|
|
11
11
|
kLogLevel,
|
|
12
|
-
kContentTypeParser
|
|
12
|
+
kContentTypeParser,
|
|
13
|
+
kRouteByFastify,
|
|
14
|
+
kRequestValidateWeakMap,
|
|
15
|
+
kReplySerializeWeakMap
|
|
13
16
|
} = require('./symbols.js')
|
|
14
17
|
|
|
15
18
|
// Objects that holds the context of every request
|
|
@@ -23,9 +26,12 @@ function Context ({
|
|
|
23
26
|
logLevel,
|
|
24
27
|
logSerializers,
|
|
25
28
|
attachValidation,
|
|
29
|
+
validatorCompiler,
|
|
30
|
+
serializerCompiler,
|
|
26
31
|
replySerializer,
|
|
27
32
|
schemaErrorFormatter,
|
|
28
|
-
server
|
|
33
|
+
server,
|
|
34
|
+
isFastify
|
|
29
35
|
}) {
|
|
30
36
|
this.schema = schema
|
|
31
37
|
this.handler = handler
|
|
@@ -50,6 +56,12 @@ function Context ({
|
|
|
50
56
|
this.attachValidation = attachValidation
|
|
51
57
|
this[kReplySerializerDefault] = replySerializer
|
|
52
58
|
this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter
|
|
59
|
+
this[kRouteByFastify] = isFastify
|
|
60
|
+
|
|
61
|
+
this[kRequestValidateWeakMap] = null
|
|
62
|
+
this[kReplySerializeWeakMap] = null
|
|
63
|
+
this.validatorCompiler = validatorCompiler || null
|
|
64
|
+
this.serializerCompiler = serializerCompiler || null
|
|
53
65
|
|
|
54
66
|
this.server = server
|
|
55
67
|
}
|
package/lib/error-serializer.js
CHANGED
|
@@ -39,7 +39,7 @@ class Serializer {
|
|
|
39
39
|
} else {
|
|
40
40
|
/* eslint no-undef: "off" */
|
|
41
41
|
const integer = this.parseInteger(i)
|
|
42
|
-
if (Number.isNaN(integer)) {
|
|
42
|
+
if (Number.isNaN(integer) || !Number.isFinite(integer)) {
|
|
43
43
|
throw new Error(`The value "${i}" cannot be converted to an integer.`)
|
|
44
44
|
} else {
|
|
45
45
|
return '' + integer
|
|
@@ -55,6 +55,8 @@ class Serializer {
|
|
|
55
55
|
const num = Number(i)
|
|
56
56
|
if (Number.isNaN(num)) {
|
|
57
57
|
throw new Error(`The value "${i}" cannot be converted to a number.`)
|
|
58
|
+
} else if (!Number.isFinite(num)) {
|
|
59
|
+
return null
|
|
58
60
|
} else {
|
|
59
61
|
return '' + num
|
|
60
62
|
}
|
|
@@ -72,44 +74,44 @@ class Serializer {
|
|
|
72
74
|
return bool === null ? 'null' : this.asBoolean(bool)
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
asDateTime (date) {
|
|
78
|
+
if (date === null) return '""'
|
|
77
79
|
if (date instanceof Date) {
|
|
78
|
-
return
|
|
80
|
+
return '"' + date.toISOString() + '"'
|
|
79
81
|
}
|
|
80
|
-
|
|
82
|
+
throw new Error(`The value "${date}" cannot be converted to a date-time.`)
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
return date === null ? 'null' : this.
|
|
85
|
+
asDateTimeNullable (date) {
|
|
86
|
+
return date === null ? 'null' : this.asDateTime(date)
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
asDate (date
|
|
88
|
-
|
|
89
|
+
asDate (date) {
|
|
90
|
+
if (date === null) return '""'
|
|
89
91
|
if (date instanceof Date) {
|
|
90
|
-
return
|
|
92
|
+
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + '"'
|
|
91
93
|
}
|
|
92
|
-
|
|
94
|
+
throw new Error(`The value "${date}" cannot be converted to a date.`)
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
asDateNullable (date
|
|
96
|
-
return date === null ? 'null' : this.asDate(date
|
|
97
|
+
asDateNullable (date) {
|
|
98
|
+
return date === null ? 'null' : this.asDate(date)
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
asTime (date
|
|
100
|
-
|
|
101
|
+
asTime (date) {
|
|
102
|
+
if (date === null) return '""'
|
|
101
103
|
if (date instanceof Date) {
|
|
102
|
-
return
|
|
104
|
+
return '"' + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + '"'
|
|
103
105
|
}
|
|
104
|
-
|
|
106
|
+
throw new Error(`The value "${date}" cannot be converted to a time.`)
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
asTimeNullable (date
|
|
108
|
-
return date === null ? 'null' : this.asTime(date
|
|
109
|
+
asTimeNullable (date) {
|
|
110
|
+
return date === null ? 'null' : this.asTime(date)
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
asString (str
|
|
112
|
-
const quotes =
|
|
113
|
+
asString (str) {
|
|
114
|
+
const quotes = '"'
|
|
113
115
|
if (str instanceof Date) {
|
|
114
116
|
return quotes + str.toISOString() + quotes
|
|
115
117
|
} else if (str === null) {
|
|
@@ -119,11 +121,6 @@ class Serializer {
|
|
|
119
121
|
} else if (typeof str !== 'string') {
|
|
120
122
|
str = str.toString()
|
|
121
123
|
}
|
|
122
|
-
// If we skipQuotes it means that we are using it as test
|
|
123
|
-
// no need to test the string length for the render
|
|
124
|
-
if (skipQuotes) {
|
|
125
|
-
return str
|
|
126
|
-
}
|
|
127
124
|
|
|
128
125
|
if (str.length < 42) {
|
|
129
126
|
return this.asStringSmall(str)
|
|
@@ -185,7 +182,7 @@ class Serializer {
|
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
function anonymous0 (input) {
|
|
188
|
-
//
|
|
185
|
+
// #
|
|
189
186
|
|
|
190
187
|
var obj = (input && typeof input.toJSON === 'function')
|
|
191
188
|
? input.toJSON()
|