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/lib/request.js
CHANGED
|
@@ -4,8 +4,24 @@ const proxyAddr = require('proxy-addr')
|
|
|
4
4
|
const semver = require('semver')
|
|
5
5
|
const warning = require('./warnings')
|
|
6
6
|
const {
|
|
7
|
-
kHasBeenDecorated
|
|
7
|
+
kHasBeenDecorated,
|
|
8
|
+
kSchemaBody,
|
|
9
|
+
kSchemaHeaders,
|
|
10
|
+
kSchemaParams,
|
|
11
|
+
kSchemaQuerystring,
|
|
12
|
+
kSchemaController,
|
|
13
|
+
kOptions,
|
|
14
|
+
kRequestValidateWeakMap
|
|
8
15
|
} = require('./symbols')
|
|
16
|
+
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors')
|
|
17
|
+
|
|
18
|
+
const HTTP_PART_SYMBOL_MAP = {
|
|
19
|
+
body: kSchemaBody,
|
|
20
|
+
headers: kSchemaHeaders,
|
|
21
|
+
params: kSchemaParams,
|
|
22
|
+
querystring: kSchemaQuerystring,
|
|
23
|
+
query: kSchemaQuerystring
|
|
24
|
+
}
|
|
9
25
|
|
|
10
26
|
function Request (id, params, req, query, log, context) {
|
|
11
27
|
this.id = id
|
|
@@ -194,6 +210,86 @@ Object.defineProperties(Request.prototype, {
|
|
|
194
210
|
set (headers) {
|
|
195
211
|
this.additionalHeaders = headers
|
|
196
212
|
}
|
|
213
|
+
},
|
|
214
|
+
getValidationFunction: {
|
|
215
|
+
value: function (httpPartOrSchema) {
|
|
216
|
+
if (typeof httpPartOrSchema === 'string') {
|
|
217
|
+
const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema]
|
|
218
|
+
return this.context[symbol]
|
|
219
|
+
} else if (typeof httpPartOrSchema === 'object') {
|
|
220
|
+
return this.context[kRequestValidateWeakMap]?.get(httpPartOrSchema)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
compileValidationSchema: {
|
|
225
|
+
value: function (schema, httpPart = null) {
|
|
226
|
+
const { method, url } = this
|
|
227
|
+
|
|
228
|
+
if (this.context[kRequestValidateWeakMap]?.has(schema)) {
|
|
229
|
+
return this.context[kRequestValidateWeakMap].get(schema)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const validatorCompiler = this.context.validatorCompiler ||
|
|
233
|
+
this.server[kSchemaController].validatorCompiler ||
|
|
234
|
+
(
|
|
235
|
+
// We compile the schemas if no custom validatorCompiler is provided
|
|
236
|
+
// nor set
|
|
237
|
+
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
|
238
|
+
this.server[kSchemaController].validatorCompiler
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
const validateFn = validatorCompiler({
|
|
242
|
+
schema,
|
|
243
|
+
method,
|
|
244
|
+
url,
|
|
245
|
+
httpPart
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
// We create a WeakMap to compile the schema only once
|
|
249
|
+
// Its done leazily to avoid add overhead by creating the WeakMap
|
|
250
|
+
// if it is not used
|
|
251
|
+
// TODO: Explore a central cache for all the schemas shared across
|
|
252
|
+
// encapsulated contexts
|
|
253
|
+
if (this.context[kRequestValidateWeakMap] == null) {
|
|
254
|
+
this.context[kRequestValidateWeakMap] = new WeakMap()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.context[kRequestValidateWeakMap].set(schema, validateFn)
|
|
258
|
+
|
|
259
|
+
return validateFn
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
validateInput: {
|
|
263
|
+
value: function (input, schema, httpPart) {
|
|
264
|
+
httpPart = typeof schema === 'string' ? schema : httpPart
|
|
265
|
+
|
|
266
|
+
const symbol = (httpPart != null && typeof httpPart === 'string') && HTTP_PART_SYMBOL_MAP[httpPart]
|
|
267
|
+
let validate
|
|
268
|
+
|
|
269
|
+
if (symbol) {
|
|
270
|
+
// Validate using the HTTP Request Part schema
|
|
271
|
+
validate = this.context[symbol]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// We cannot compile if the schema is missed
|
|
275
|
+
if (validate == null && (schema == null ||
|
|
276
|
+
typeof schema !== 'object' ||
|
|
277
|
+
Array.isArray(schema))
|
|
278
|
+
) {
|
|
279
|
+
throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (validate == null) {
|
|
283
|
+
if (this.context[kRequestValidateWeakMap]?.has(schema)) {
|
|
284
|
+
validate = this.context[kRequestValidateWeakMap].get(schema)
|
|
285
|
+
} else {
|
|
286
|
+
// We proceed to compile if there's no validate function yet
|
|
287
|
+
validate = this.compileValidationSchema(schema, httpPart)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return validate(input)
|
|
292
|
+
}
|
|
197
293
|
}
|
|
198
294
|
})
|
|
199
295
|
|
package/lib/route.js
CHANGED
|
@@ -241,6 +241,8 @@ function buildRouting (options) {
|
|
|
241
241
|
attachValidation: opts.attachValidation,
|
|
242
242
|
schemaErrorFormatter: opts.schemaErrorFormatter,
|
|
243
243
|
replySerializer: this[kReplySerializerDefault],
|
|
244
|
+
validatorCompiler: opts.validatorCompiler,
|
|
245
|
+
serializerCompiler: opts.serializerCompiler,
|
|
244
246
|
server: this,
|
|
245
247
|
isFastify
|
|
246
248
|
})
|
package/lib/symbols.js
CHANGED
|
@@ -9,6 +9,12 @@ const keys = {
|
|
|
9
9
|
kLogLevel: Symbol('fastify.logLevel'),
|
|
10
10
|
kLogSerializers: Symbol('fastify.logSerializers'),
|
|
11
11
|
kHooks: Symbol('fastify.hooks'),
|
|
12
|
+
kContentTypeParser: Symbol('fastify.contentTypeParser'),
|
|
13
|
+
kState: Symbol('fastify.state'),
|
|
14
|
+
kOptions: Symbol('fastify.options'),
|
|
15
|
+
kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
|
|
16
|
+
kPluginNameChain: Symbol('fastify.pluginNameChain'),
|
|
17
|
+
// Schema
|
|
12
18
|
kSchemaController: Symbol('fastify.schemaController'),
|
|
13
19
|
kSchemaHeaders: Symbol('headers-schema'),
|
|
14
20
|
kSchemaParams: Symbol('params-schema'),
|
|
@@ -16,17 +22,20 @@ const keys = {
|
|
|
16
22
|
kSchemaBody: Symbol('body-schema'),
|
|
17
23
|
kSchemaResponse: Symbol('response-schema'),
|
|
18
24
|
kSchemaErrorFormatter: Symbol('fastify.schemaErrorFormatter'),
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
kReply: Symbol('fastify.Reply'),
|
|
25
|
+
kSchemaVisited: Symbol('fastify.schemas.visited'),
|
|
26
|
+
// Request
|
|
22
27
|
kRequest: Symbol('fastify.Request'),
|
|
28
|
+
kRequestValidateFns: Symbol('fastify.request.cache.validateFns'),
|
|
23
29
|
kRequestPayloadStream: Symbol('fastify.RequestPayloadStream'),
|
|
24
30
|
kRequestAcceptVersion: Symbol('fastify.RequestAcceptVersion'),
|
|
25
|
-
|
|
31
|
+
// 404
|
|
26
32
|
kFourOhFour: Symbol('fastify.404'),
|
|
33
|
+
kCanSetNotFoundHandler: Symbol('fastify.canSetNotFoundHandler'),
|
|
27
34
|
kFourOhFourLevelInstance: Symbol('fastify.404LogLevelInstance'),
|
|
28
35
|
kFourOhFourContext: Symbol('fastify.404ContextKey'),
|
|
29
36
|
kDefaultJsonParse: Symbol('fastify.defaultJSONParse'),
|
|
37
|
+
// Reply
|
|
38
|
+
kReply: Symbol('fastify.Reply'),
|
|
30
39
|
kReplySerializer: Symbol('fastify.reply.serializer'),
|
|
31
40
|
kReplyIsError: Symbol('fastify.reply.isError'),
|
|
32
41
|
kReplyHeaders: Symbol('fastify.reply.headers'),
|
|
@@ -38,11 +47,8 @@ const keys = {
|
|
|
38
47
|
kReplyEndTime: Symbol('fastify.reply.endTime'),
|
|
39
48
|
kReplyErrorHandlerCalled: Symbol('fastify.reply.errorHandlerCalled'),
|
|
40
49
|
kReplyIsRunningOnErrorHook: Symbol('fastify.reply.isRunningOnErrorHook'),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
kOptions: Symbol('fastify.options'),
|
|
44
|
-
kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
|
|
45
|
-
kPluginNameChain: Symbol('fastify.pluginNameChain'),
|
|
50
|
+
kReplySerializerDefault: Symbol('fastify.replySerializerDefault'),
|
|
51
|
+
kReplySerializeWeakMap: Symbol('fastify.reply.cache.serializeFns'),
|
|
46
52
|
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
|
47
53
|
kTestInternals: Symbol('fastify.testInternals'),
|
|
48
54
|
kErrorHandler: Symbol('fastify.errorHandler'),
|
package/package.json
CHANGED
|
@@ -58,6 +58,21 @@ test('getParser', t => {
|
|
|
58
58
|
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
+
test('should return matching parser with caching', t => {
|
|
62
|
+
t.plan(6)
|
|
63
|
+
|
|
64
|
+
const fastify = Fastify()
|
|
65
|
+
|
|
66
|
+
fastify.addContentTypeParser('text/html', first)
|
|
67
|
+
|
|
68
|
+
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
|
|
69
|
+
t.equal(fastify[keys.kContentTypeParser].cache.size, 0)
|
|
70
|
+
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
|
|
71
|
+
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
|
|
72
|
+
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
|
|
73
|
+
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
|
|
74
|
+
})
|
|
75
|
+
|
|
61
76
|
test('should prefer content type parser with string value', t => {
|
|
62
77
|
t.plan(2)
|
|
63
78
|
|