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/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
- kReplySerializerDefault: Symbol('fastify.replySerializerDefault'),
20
- kContentTypeParser: Symbol('fastify.contentTypeParser'),
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
- kCanSetNotFoundHandler: Symbol('fastify.canSetNotFoundHandler'),
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
- kSchemaVisited: Symbol('fastify.schemas.visited'),
42
- kState: Symbol('fastify.state'),
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -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