fastify 4.2.1 → 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/docs/Guides/Ecosystem.md +2 -0
- package/docs/Reference/HTTP2.md +1 -3
- package/docs/Reference/Reply.md +176 -0
- package/docs/Reference/Request.md +171 -0
- package/fastify.d.ts +1 -1
- package/fastify.js +2 -2
- package/lib/contentTypeParser.js +10 -2
- package/lib/context.js +10 -1
- package/lib/errors.js +8 -0
- package/lib/reply.js +80 -2
- package/lib/request.js +97 -1
- package/lib/route.js +2 -0
- package/lib/symbols.js +15 -9
- package/package.json +1 -1
- package/test/content-parser.test.js +15 -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/request-error.test.js +44 -1
- package/test/types/hooks.test-d.ts +1 -2
- package/test/types/import.ts +1 -1
- package/test/types/request.test-d.ts +1 -1
- package/test/types/type-provider.test-d.ts +76 -6
- package/types/hooks.d.ts +19 -39
- package/types/instance.d.ts +19 -39
- package/types/reply.d.ts +5 -0
- package/types/request.d.ts +16 -3
- package/types/route.d.ts +23 -29
- package/types/type-provider.d.ts +7 -6
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -169,6 +169,8 @@ section.
|
|
|
169
169
|
- [`cls-rtracer`](https://github.com/puzpuzpuz/cls-rtracer) Fastify middleware
|
|
170
170
|
for CLS-based request ID generation. An out-of-the-box solution for adding
|
|
171
171
|
request IDs into your logs.
|
|
172
|
+
- [`electron-server`](https://github.com/anonrig/electron-server) A plugin for
|
|
173
|
+
using Fastify without the need of consuming a port on Electron apps.
|
|
172
174
|
- [`fast-water`](https://github.com/tswayne/fast-water) A Fastify plugin for
|
|
173
175
|
waterline. Decorates Fastify with waterline models.
|
|
174
176
|
- [`fastify-405`](https://github.com/Eomm/fastify-405) Fastify plugin that adds
|
package/docs/Reference/HTTP2.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## HTTP2
|
|
4
4
|
|
|
5
|
-
_Fastify_
|
|
6
|
-
which includes HTTP2 without a flag; HTTP2 is supported over either HTTPS or
|
|
7
|
-
plaintext.
|
|
5
|
+
_Fastify_ supports HTTP2 over either HTTPS (h2) or plaintext (h2c).
|
|
8
6
|
|
|
9
7
|
Currently, none of the HTTP2-specific APIs are available through _Fastify_, but
|
|
10
8
|
Node's `req` and `res` can be accessed through our `Request` and `Reply`
|
package/docs/Reference/Reply.md
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
- [.callNotFound()](#callnotfound)
|
|
21
21
|
- [.getResponseTime()](#getresponsetime)
|
|
22
22
|
- [.type(contentType)](#typecontenttype)
|
|
23
|
+
- [.getSerializationFunction(schema | httpStatus)](#getserializationfunction)
|
|
24
|
+
- [.compileSerializationSchema(schema, httpStatus)](#compileserializationschema)
|
|
25
|
+
- [.serializeInput(data, [schema | httpStatus], [httpStatus])](#serializeinput)
|
|
23
26
|
- [.serializer(func)](#serializerfunc)
|
|
24
27
|
- [.raw](#raw)
|
|
25
28
|
- [.sent](#sent)
|
|
@@ -60,6 +63,16 @@ object that exposes the following functions and properties:
|
|
|
60
63
|
- `.serialize(payload)` - Serializes the specified payload using the default
|
|
61
64
|
JSON serializer or using the custom serializer (if one is set) and returns the
|
|
62
65
|
serialized payload.
|
|
66
|
+
- `.getSerializationFunction(schema | httpStatus)` - Returns the serialization
|
|
67
|
+
function for the specified schema or http status, if any of either are set.
|
|
68
|
+
- `.compileSerializationSchema(schema, httpStatus)` - Compiles the specified
|
|
69
|
+
schema and returns a serialization function using the default (or customized)
|
|
70
|
+
`SerializerCompiler`. The optional `httpStatus` is forwarded to the
|
|
71
|
+
`SerializerCompiler` if provided, default to `undefined`.
|
|
72
|
+
- `.serializeInput(data, schema, [,httpStatus])` - Serializes the specified data
|
|
73
|
+
using the specified schema and returns the serialized payload.
|
|
74
|
+
If the optional `httpStatus` is provided, the function will use the serializer
|
|
75
|
+
function given for that HTTP Status Code. Default to `undefined`.
|
|
63
76
|
- `.serializer(function)` - Sets a custom serializer for the payload.
|
|
64
77
|
- `.send(payload)` - Sends the payload to the user, could be a plain text, a
|
|
65
78
|
buffer, JSON, stream, or an Error object.
|
|
@@ -326,6 +339,169 @@ reply.type('text/html')
|
|
|
326
339
|
If the `Content-Type` has a JSON subtype, and the charset parameter is not set,
|
|
327
340
|
`utf-8` will be used as the charset by default.
|
|
328
341
|
|
|
342
|
+
### .getSerializationFunction(schema | httpStatus)
|
|
343
|
+
<a id="getserializationfunction"></a>
|
|
344
|
+
|
|
345
|
+
By calling this function using a provided `schema` or `httpStatus`,
|
|
346
|
+
it will return a `serialzation` function that can be used to
|
|
347
|
+
serialize diverse inputs. It returns `undefined` if no
|
|
348
|
+
serialization function was found using either of the provided inputs.
|
|
349
|
+
|
|
350
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
351
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
const serialize = reply
|
|
355
|
+
.getSerializationFunction({
|
|
356
|
+
type: 'object',
|
|
357
|
+
properties: {
|
|
358
|
+
foo: {
|
|
359
|
+
type: 'string'
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
364
|
+
|
|
365
|
+
// or
|
|
366
|
+
|
|
367
|
+
const serialize = reply
|
|
368
|
+
.getSerializationFunction(200)
|
|
369
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
See [.compileSerializationSchema(schema, [httpStatus])](#compileserializationschema)
|
|
373
|
+
for more information on how to compile serialization schemas.
|
|
374
|
+
|
|
375
|
+
### .compileSerializationSchema(schema, httpStatus)
|
|
376
|
+
<a id="compileserializationschema"></a>
|
|
377
|
+
|
|
378
|
+
This function will compile a serialization schema and
|
|
379
|
+
return a function that can be used to serialize data.
|
|
380
|
+
The function returned (a.k.a. _serialization function_) returned is compiled
|
|
381
|
+
by using the provided `SerializerCompiler`. Also this is cached by using
|
|
382
|
+
a `WeakMap` for reducing compilation calls.
|
|
383
|
+
|
|
384
|
+
The optional paramater `httpStatus`, if provided, is forwarded directly
|
|
385
|
+
the `SerializerCompiler`, so it can be used to compile the serialization
|
|
386
|
+
function if a custom `SerializerCompiler` is used.
|
|
387
|
+
|
|
388
|
+
This heavily depends of the `schema#responses` attached to the route, or
|
|
389
|
+
the serialization functions compiled by using `compileSerializationSchema`.
|
|
390
|
+
|
|
391
|
+
```js
|
|
392
|
+
const serialize = reply
|
|
393
|
+
.compileSerializationSchema({
|
|
394
|
+
type: 'object',
|
|
395
|
+
properties: {
|
|
396
|
+
foo: {
|
|
397
|
+
type: 'string'
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
})
|
|
401
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
402
|
+
|
|
403
|
+
// or
|
|
404
|
+
|
|
405
|
+
const serialize = reply
|
|
406
|
+
.compileSerializationSchema({
|
|
407
|
+
type: 'object',
|
|
408
|
+
properties: {
|
|
409
|
+
foo: {
|
|
410
|
+
type: 'string'
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}, 200)
|
|
414
|
+
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Note that you should be careful when using this function, as it will cache
|
|
418
|
+
the compiled serialization functions based on the schema provided. If the
|
|
419
|
+
schemas provided is mutated or changed, the serialization functions will not
|
|
420
|
+
detect that the schema has been altered and for instance it will reuse the
|
|
421
|
+
previously compiled serialization function based on the reference of the schema
|
|
422
|
+
previously provided.
|
|
423
|
+
|
|
424
|
+
If there's a need to change the properties of a schema, always opt to create
|
|
425
|
+
a totally new object, otherwise the implementation won't benefit from the cache
|
|
426
|
+
mechanism.
|
|
427
|
+
|
|
428
|
+
:Using the following schema as example:
|
|
429
|
+
```js
|
|
430
|
+
const schema1 = {
|
|
431
|
+
type: 'object',
|
|
432
|
+
properties: {
|
|
433
|
+
foo: {
|
|
434
|
+
type: 'string'
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
*Not*
|
|
441
|
+
```js
|
|
442
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
443
|
+
|
|
444
|
+
// Later on...
|
|
445
|
+
schema1.properties.foo.type. = 'integer'
|
|
446
|
+
const newSerialize = reply.compileSerializationSchema(schema1)
|
|
447
|
+
|
|
448
|
+
console.log(newSerialize === serialize) // true
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
*Instead*
|
|
452
|
+
```js
|
|
453
|
+
const serialize = reply.compileSerializationSchema(schema1)
|
|
454
|
+
|
|
455
|
+
// Later on...
|
|
456
|
+
const newSchema = Object.assign({}, schema1)
|
|
457
|
+
newSchema.properties.foo.type = 'integer'
|
|
458
|
+
|
|
459
|
+
const newSerialize = reply.compileSerializationSchema(newSchema)
|
|
460
|
+
|
|
461
|
+
console.log(newSerialize === serialize) // false
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### .serializeInput(data, [schema | httpStatus], [httpStatus])
|
|
465
|
+
<a id="serializeinput"></a>
|
|
466
|
+
|
|
467
|
+
This function will serialize the input data based on the provided schema,
|
|
468
|
+
or http status code. If both provided, the `httpStatus` will take presedence.
|
|
469
|
+
|
|
470
|
+
If there is not a serialization function for a given `schema`, a new serialization
|
|
471
|
+
function will be compiled forwarding the `httpStatus` if provided.
|
|
472
|
+
|
|
473
|
+
```js
|
|
474
|
+
reply
|
|
475
|
+
.serializeInput({ foo: 'bar'}, {
|
|
476
|
+
type: 'object',
|
|
477
|
+
properties: {
|
|
478
|
+
foo: {
|
|
479
|
+
type: 'string'
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}) // '{"foo":"bar"}'
|
|
483
|
+
|
|
484
|
+
// or
|
|
485
|
+
|
|
486
|
+
reply
|
|
487
|
+
.serializeInput({ foo: 'bar'}, {
|
|
488
|
+
type: 'object',
|
|
489
|
+
properties: {
|
|
490
|
+
foo: {
|
|
491
|
+
type: 'string'
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}, 200) // '{"foo":"bar"}'
|
|
495
|
+
|
|
496
|
+
// or
|
|
497
|
+
|
|
498
|
+
reply
|
|
499
|
+
.serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
See [.compileSerializationSchema(schema, [httpStatus])](#compileserializationschema)
|
|
503
|
+
for more information on how to compile serialization schemas.
|
|
504
|
+
|
|
329
505
|
### .serializer(func)
|
|
330
506
|
<a id="serializer"></a>
|
|
331
507
|
|
|
@@ -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.
|
package/fastify.d.ts
CHANGED
|
@@ -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)
|
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
|
@@ -10,7 +10,9 @@ const {
|
|
|
10
10
|
kBodyLimit,
|
|
11
11
|
kLogLevel,
|
|
12
12
|
kContentTypeParser,
|
|
13
|
-
kRouteByFastify
|
|
13
|
+
kRouteByFastify,
|
|
14
|
+
kRequestValidateWeakMap,
|
|
15
|
+
kReplySerializeWeakMap
|
|
14
16
|
} = require('./symbols.js')
|
|
15
17
|
|
|
16
18
|
// Objects that holds the context of every request
|
|
@@ -24,6 +26,8 @@ function Context ({
|
|
|
24
26
|
logLevel,
|
|
25
27
|
logSerializers,
|
|
26
28
|
attachValidation,
|
|
29
|
+
validatorCompiler,
|
|
30
|
+
serializerCompiler,
|
|
27
31
|
replySerializer,
|
|
28
32
|
schemaErrorFormatter,
|
|
29
33
|
server,
|
|
@@ -54,6 +58,11 @@ function Context ({
|
|
|
54
58
|
this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter
|
|
55
59
|
this[kRouteByFastify] = isFastify
|
|
56
60
|
|
|
61
|
+
this[kRequestValidateWeakMap] = null
|
|
62
|
+
this[kReplySerializeWeakMap] = null
|
|
63
|
+
this.validatorCompiler = validatorCompiler || null
|
|
64
|
+
this.serializerCompiler = serializerCompiler || null
|
|
65
|
+
|
|
57
66
|
this.server = server
|
|
58
67
|
}
|
|
59
68
|
|
package/lib/errors.js
CHANGED
|
@@ -160,6 +160,14 @@ const codes = {
|
|
|
160
160
|
'FST_ERR_BAD_TRAILER_VALUE',
|
|
161
161
|
"Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function."
|
|
162
162
|
),
|
|
163
|
+
FST_ERR_MISSING_SERIALIZATION_FN: createError(
|
|
164
|
+
'FST_ERR_MISSING_SERIALIZATION_FN',
|
|
165
|
+
'Missing serialization function. Key "%s"'
|
|
166
|
+
),
|
|
167
|
+
FST_ERR_REQ_INVALID_VALIDATION_INVOCATION: createError(
|
|
168
|
+
'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION',
|
|
169
|
+
'Invalid validation invocation. Missing validation function for HTTP part "%s" nor schema provided.'
|
|
170
|
+
),
|
|
163
171
|
|
|
164
172
|
/**
|
|
165
173
|
* schemas
|
package/lib/reply.js
CHANGED
|
@@ -16,7 +16,11 @@ const {
|
|
|
16
16
|
kReplyHasStatusCode,
|
|
17
17
|
kReplyIsRunningOnErrorHook,
|
|
18
18
|
kReplyNextErrorHandler,
|
|
19
|
-
kDisableRequestLogging
|
|
19
|
+
kDisableRequestLogging,
|
|
20
|
+
kSchemaResponse,
|
|
21
|
+
kReplySerializeWeakMap,
|
|
22
|
+
kSchemaController,
|
|
23
|
+
kOptions
|
|
20
24
|
} = require('./symbols.js')
|
|
21
25
|
const { hookRunner, hookIterator, onSendHookRunner } = require('./hooks')
|
|
22
26
|
|
|
@@ -38,7 +42,8 @@ const {
|
|
|
38
42
|
FST_ERR_SEND_INSIDE_ONERR,
|
|
39
43
|
FST_ERR_BAD_STATUS_CODE,
|
|
40
44
|
FST_ERR_BAD_TRAILER_NAME,
|
|
41
|
-
FST_ERR_BAD_TRAILER_VALUE
|
|
45
|
+
FST_ERR_BAD_TRAILER_VALUE,
|
|
46
|
+
FST_ERR_MISSING_SERIALIZATION_FN
|
|
42
47
|
} = require('./errors')
|
|
43
48
|
const warning = require('./warnings')
|
|
44
49
|
|
|
@@ -299,6 +304,79 @@ Reply.prototype.code = function (code) {
|
|
|
299
304
|
|
|
300
305
|
Reply.prototype.status = Reply.prototype.code
|
|
301
306
|
|
|
307
|
+
Reply.prototype.getSerializationFunction = function (schemaOrStatus) {
|
|
308
|
+
let serialize
|
|
309
|
+
|
|
310
|
+
if (typeof schemaOrStatus === 'string' || typeof schemaOrStatus === 'number') {
|
|
311
|
+
serialize = this.context[kSchemaResponse]?.[schemaOrStatus]
|
|
312
|
+
} else if (typeof schemaOrStatus === 'object') {
|
|
313
|
+
serialize = this.context[kReplySerializeWeakMap]?.get(schemaOrStatus)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return serialize
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null) {
|
|
320
|
+
const { request } = this
|
|
321
|
+
const { method, url } = request
|
|
322
|
+
|
|
323
|
+
// Check if serialize function already compiled
|
|
324
|
+
if (this.context[kReplySerializeWeakMap]?.has(schema)) {
|
|
325
|
+
return this.context[kReplySerializeWeakMap].get(schema)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const serializerCompiler = this.context.serializerCompiler ||
|
|
329
|
+
this.server[kSchemaController].serializerCompiler ||
|
|
330
|
+
(
|
|
331
|
+
// We compile the schemas if no custom serializerCompiler is provided
|
|
332
|
+
// nor set
|
|
333
|
+
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
|
|
334
|
+
this.server[kSchemaController].serializerCompiler
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
const serializeFn = serializerCompiler({
|
|
338
|
+
schema,
|
|
339
|
+
method,
|
|
340
|
+
url,
|
|
341
|
+
httpStatus
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
// We create a WeakMap to compile the schema only once
|
|
345
|
+
// Its done leazily to avoid add overhead by creating the WeakMap
|
|
346
|
+
// if it is not used
|
|
347
|
+
// TODO: Explore a central cache for all the schemas shared across
|
|
348
|
+
// encapsulated contexts
|
|
349
|
+
if (this.context[kReplySerializeWeakMap] == null) {
|
|
350
|
+
this.context[kReplySerializeWeakMap] = new WeakMap()
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
this.context[kReplySerializeWeakMap].set(schema, serializeFn)
|
|
354
|
+
|
|
355
|
+
return serializeFn
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
Reply.prototype.serializeInput = function (input, schema, httpStatus) {
|
|
359
|
+
let serialize
|
|
360
|
+
httpStatus = typeof schema === 'string' || typeof schema === 'number'
|
|
361
|
+
? schema
|
|
362
|
+
: httpStatus
|
|
363
|
+
|
|
364
|
+
if (httpStatus != null) {
|
|
365
|
+
serialize = this.context[kSchemaResponse]?.[httpStatus]
|
|
366
|
+
|
|
367
|
+
if (serialize == null) throw new FST_ERR_MISSING_SERIALIZATION_FN(httpStatus)
|
|
368
|
+
} else {
|
|
369
|
+
// Check if serialize function already compiled
|
|
370
|
+
if (this.context[kReplySerializeWeakMap]?.has(schema)) {
|
|
371
|
+
serialize = this.context[kReplySerializeWeakMap].get(schema)
|
|
372
|
+
} else {
|
|
373
|
+
serialize = this.compileSerializationSchema(schema, httpStatus)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return serialize(input)
|
|
378
|
+
}
|
|
379
|
+
|
|
302
380
|
Reply.prototype.serialize = function (payload) {
|
|
303
381
|
if (this[kReplySerializer] !== null) {
|
|
304
382
|
return this[kReplySerializer](payload)
|