fastify 3.27.4 → 4.0.0-alpha.3

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.
Files changed (168) hide show
  1. package/.taprc +3 -0
  2. package/README.md +7 -7
  3. package/build/build-error-serializer.js +27 -0
  4. package/build/build-validation.js +47 -35
  5. package/docs/Guides/Database.md +320 -0
  6. package/docs/Guides/Ecosystem.md +9 -0
  7. package/docs/Guides/Getting-Started.md +7 -7
  8. package/docs/Guides/Plugins-Guide.md +1 -1
  9. package/docs/Guides/Serverless.md +3 -3
  10. package/docs/Guides/Testing.md +2 -2
  11. package/docs/Migration-Guide-V4.md +12 -0
  12. package/docs/Reference/ContentTypeParser.md +4 -0
  13. package/docs/Reference/Decorators.md +2 -2
  14. package/docs/Reference/Encapsulation.md +2 -2
  15. package/docs/Reference/Errors.md +51 -6
  16. package/docs/Reference/HTTP2.md +3 -3
  17. package/docs/Reference/Hooks.md +4 -7
  18. package/docs/Reference/LTS.md +5 -4
  19. package/docs/Reference/Plugins.md +3 -3
  20. package/docs/Reference/Reply.md +73 -22
  21. package/docs/Reference/Request.md +1 -3
  22. package/docs/Reference/Routes.md +22 -15
  23. package/docs/Reference/Server.md +69 -119
  24. package/docs/Reference/TypeScript.md +20 -22
  25. package/docs/Reference/Validation-and-Serialization.md +30 -55
  26. package/docs/Type-Providers.md +257 -0
  27. package/examples/asyncawait.js +1 -1
  28. package/examples/benchmark/hooks-benchmark-async-await.js +1 -1
  29. package/examples/benchmark/hooks-benchmark.js +1 -1
  30. package/examples/benchmark/simple.js +1 -1
  31. package/examples/hooks.js +2 -2
  32. package/examples/http2.js +1 -1
  33. package/examples/https.js +1 -1
  34. package/examples/parser.js +13 -3
  35. package/examples/route-prefix.js +1 -1
  36. package/examples/shared-schema.js +1 -1
  37. package/examples/simple-stream.js +18 -0
  38. package/examples/simple.js +1 -1
  39. package/examples/simple.mjs +1 -1
  40. package/examples/typescript-server.ts +1 -1
  41. package/examples/use-plugin.js +1 -1
  42. package/fastify.d.ts +34 -22
  43. package/fastify.js +40 -36
  44. package/lib/configValidator.js +902 -1023
  45. package/lib/contentTypeParser.js +6 -16
  46. package/lib/context.js +36 -10
  47. package/lib/decorate.js +3 -1
  48. package/lib/error-handler.js +158 -0
  49. package/lib/error-serializer.js +257 -0
  50. package/lib/errors.js +51 -9
  51. package/lib/fourOhFour.js +31 -20
  52. package/lib/handleRequest.js +10 -13
  53. package/lib/hooks.js +14 -9
  54. package/lib/pluginOverride.js +0 -3
  55. package/lib/pluginUtils.js +3 -2
  56. package/lib/reply.js +121 -175
  57. package/lib/request.js +13 -10
  58. package/lib/route.js +131 -138
  59. package/lib/schema-controller.js +2 -2
  60. package/lib/schemas.js +27 -1
  61. package/lib/server.js +242 -116
  62. package/lib/symbols.js +5 -3
  63. package/lib/validation.js +11 -9
  64. package/lib/warnings.js +4 -12
  65. package/lib/wrapThenable.js +4 -11
  66. package/package.json +37 -39
  67. package/test/404s.test.js +258 -125
  68. package/test/500s.test.js +3 -3
  69. package/test/als.test.js +1 -1
  70. package/test/async-await.test.js +20 -76
  71. package/test/bodyLimit.test.js +1 -1
  72. package/test/build-certificate.js +6 -7
  73. package/test/case-insensitive.test.js +4 -4
  74. package/test/close-pipelining.test.js +2 -2
  75. package/test/close.test.js +11 -11
  76. package/test/content-parser.test.js +32 -0
  77. package/test/context-config.test.js +52 -0
  78. package/test/custom-http-server.test.js +14 -7
  79. package/test/custom-parser-async.test.js +1 -66
  80. package/test/custom-parser.test.js +92 -159
  81. package/test/custom-querystring-parser.test.js +3 -3
  82. package/test/decorator.test.js +11 -13
  83. package/test/delete.test.js +6 -6
  84. package/test/encapsulated-error-handler.test.js +50 -0
  85. package/test/esm/index.test.js +0 -14
  86. package/test/fastify-instance.test.js +4 -4
  87. package/test/fluent-schema.test.js +4 -4
  88. package/test/genReqId.test.js +1 -1
  89. package/test/get.test.js +4 -4
  90. package/test/handler-context.test.js +2 -2
  91. package/test/head.test.js +1 -1
  92. package/test/helper.js +19 -4
  93. package/test/hooks-async.test.js +15 -48
  94. package/test/hooks.on-ready.test.js +10 -5
  95. package/test/hooks.test.js +78 -119
  96. package/test/http2/closing.test.js +10 -16
  97. package/test/http2/constraint.test.js +1 -1
  98. package/test/http2/head.test.js +1 -1
  99. package/test/http2/plain.test.js +1 -1
  100. package/test/http2/secure-with-fallback.test.js +1 -1
  101. package/test/http2/secure.test.js +1 -1
  102. package/test/http2/unknown-http-method.test.js +4 -10
  103. package/test/https/custom-https-server.test.js +12 -6
  104. package/test/https/https.test.js +1 -1
  105. package/test/input-validation.js +3 -3
  106. package/test/internals/handleRequest.test.js +6 -43
  107. package/test/internals/initialConfig.test.js +41 -12
  108. package/test/internals/logger.test.js +2 -2
  109. package/test/internals/reply.test.js +317 -48
  110. package/test/internals/request.test.js +13 -7
  111. package/test/internals/server.test.js +88 -0
  112. package/test/listen.deprecated.test.js +202 -0
  113. package/test/listen.test.js +140 -145
  114. package/test/logger.test.js +82 -42
  115. package/test/maxRequestsPerSocket.test.js +8 -6
  116. package/test/middleware.test.js +2 -25
  117. package/test/nullable-validation.test.js +53 -16
  118. package/test/output-validation.test.js +1 -1
  119. package/test/plugin.test.js +47 -21
  120. package/test/pretty-print.test.js +22 -10
  121. package/test/promises.test.js +1 -1
  122. package/test/proto-poisoning.test.js +6 -6
  123. package/test/register.test.js +3 -3
  124. package/test/reply-error.test.js +126 -15
  125. package/test/reply-trailers.test.js +270 -0
  126. package/test/request-error.test.js +3 -6
  127. package/test/route-hooks.test.js +18 -18
  128. package/test/route-prefix.test.js +2 -1
  129. package/test/route.test.js +206 -22
  130. package/test/router-options.test.js +2 -2
  131. package/test/schema-examples.test.js +11 -5
  132. package/test/schema-feature.test.js +25 -20
  133. package/test/schema-serialization.test.js +9 -9
  134. package/test/schema-special-usage.test.js +5 -153
  135. package/test/schema-validation.test.js +9 -9
  136. package/test/skip-reply-send.test.js +2 -2
  137. package/test/stream.test.js +82 -23
  138. package/test/throw.test.js +8 -5
  139. package/test/trust-proxy.test.js +6 -6
  140. package/test/type-provider.test.js +20 -0
  141. package/test/types/fastify.test-d.ts +10 -18
  142. package/test/types/hooks.test-d.ts +61 -5
  143. package/test/types/import.js +2 -0
  144. package/test/types/import.ts +1 -0
  145. package/test/types/instance.test-d.ts +68 -17
  146. package/test/types/logger.test-d.ts +44 -15
  147. package/test/types/reply.test-d.ts +2 -1
  148. package/test/types/request.test-d.ts +71 -1
  149. package/test/types/route.test-d.ts +8 -2
  150. package/test/types/schema.test-d.ts +2 -39
  151. package/test/types/type-provider.test-d.ts +424 -0
  152. package/test/url-rewriting.test.js +3 -3
  153. package/test/validation-error-handling.test.js +8 -8
  154. package/test/versioned-routes.test.js +30 -18
  155. package/test/wrapThenable.test.js +7 -6
  156. package/types/content-type-parser.d.ts +17 -8
  157. package/types/hooks.d.ts +182 -85
  158. package/types/instance.d.ts +286 -118
  159. package/types/logger.d.ts +18 -104
  160. package/types/plugin.d.ts +10 -4
  161. package/types/reply.d.ts +18 -12
  162. package/types/request.d.ts +13 -8
  163. package/types/route.d.ts +62 -34
  164. package/types/schema.d.ts +1 -1
  165. package/types/type-provider.d.ts +99 -0
  166. package/types/utils.d.ts +1 -1
  167. package/lib/schema-compilers.js +0 -12
  168. package/test/emit-warning.test.js +0 -166
package/lib/route.js CHANGED
@@ -19,6 +19,7 @@ const {
19
19
  FST_ERR_SCH_VALIDATION_BUILD,
20
20
  FST_ERR_SCH_SERIALIZATION_BUILD,
21
21
  FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
22
+ FST_ERR_DUPLICATED_ROUTE,
22
23
  FST_ERR_INVALID_URL
23
24
  } = require('./errors')
24
25
 
@@ -27,19 +28,17 @@ const {
27
28
  kLogLevel,
28
29
  kLogSerializers,
29
30
  kHooks,
30
- kHooksDeprecatedPreParsing,
31
31
  kSchemaController,
32
32
  kOptions,
33
- kContentTypeParser,
34
- kReply,
35
33
  kReplySerializerDefault,
36
34
  kReplyIsError,
37
- kRequest,
38
35
  kRequestPayloadStream,
39
36
  kDisableRequestLogging,
40
37
  kSchemaErrorFormatter,
41
- kErrorHandler
38
+ kErrorHandler,
39
+ kHasBeenDecorated
42
40
  } = require('./symbols.js')
41
+ const { buildErrorHandler } = require('./error-handler')
43
42
 
44
43
  function buildRouting (options) {
45
44
  const { keepAliveConnections } = options
@@ -136,22 +135,17 @@ function buildRouting (options) {
136
135
 
137
136
  throwIfAlreadyStarted('Cannot add route when fastify instance is already started!')
138
137
 
138
+ const path = opts.url || opts.path || ''
139
+
139
140
  if (Array.isArray(opts.method)) {
140
141
  // eslint-disable-next-line no-var
141
142
  for (var i = 0; i < opts.method.length; ++i) {
142
- const method = opts.method[i]
143
- if (supportedMethods.indexOf(method) === -1) {
144
- throw new Error(`${method} method is not supported!`)
145
- }
143
+ validateMethodAndSchemaBodyOption(opts.method[i], path, opts.schema)
146
144
  }
147
145
  } else {
148
- if (supportedMethods.indexOf(opts.method) === -1) {
149
- throw new Error(`${opts.method} method is not supported!`)
150
- }
146
+ validateMethodAndSchemaBodyOption(opts.method, path, opts.schema)
151
147
  }
152
148
 
153
- const path = opts.url || opts.path
154
-
155
149
  if (!opts.handler) {
156
150
  throw new Error(`Missing handler function for ${opts.method}:${path} route.`)
157
151
  }
@@ -164,42 +158,33 @@ function buildRouting (options) {
164
158
 
165
159
  const prefix = this[kRoutePrefix]
166
160
 
167
- this.after((notHandledErr, done) => {
168
- if (path === '/' && prefix.length && opts.method !== 'HEAD') {
169
- switch (opts.prefixTrailingSlash) {
170
- case 'slash':
171
- afterRouteAdded.call(this, { path }, notHandledErr, done)
172
- break
173
- case 'no-slash':
174
- afterRouteAdded.call(this, { path: '' }, notHandledErr, done)
175
- break
176
- case 'both':
177
- default:
178
- afterRouteAdded.call(this, { path: '' }, notHandledErr, done)
179
- // If ignoreTrailingSlash is set to true we need to add only the '' route to prevent adding an incomplete one.
180
- if (ignoreTrailingSlash !== true) {
181
- afterRouteAdded.call(this, { path, prefixing: true }, notHandledErr, done)
182
- }
183
- }
184
- } else if (path && path[0] === '/' && prefix.endsWith('/')) {
185
- // Ensure that '/prefix/' + '/route' gets registered as '/prefix/route'
186
- afterRouteAdded.call(this, { path: path.slice(1) }, notHandledErr, done)
187
- } else {
188
- afterRouteAdded.call(this, { path }, notHandledErr, done)
161
+ if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
162
+ switch (opts.prefixTrailingSlash) {
163
+ case 'slash':
164
+ addNewRoute.call(this, path)
165
+ break
166
+ case 'no-slash':
167
+ addNewRoute.call(this, '')
168
+ break
169
+ case 'both':
170
+ default:
171
+ addNewRoute.call(this, '')
172
+ // If ignoreTrailingSlash is set to true we need to add only the '' route to prevent adding an incomplete one.
173
+ if (ignoreTrailingSlash !== true) {
174
+ addNewRoute.call(this, path, true)
175
+ }
189
176
  }
190
- })
177
+ } else if (path[0] === '/' && prefix.endsWith('/')) {
178
+ // Ensure that '/prefix/' + '/route' gets registered as '/prefix/route'
179
+ addNewRoute.call(this, path.slice(1))
180
+ } else {
181
+ addNewRoute.call(this, path)
182
+ }
191
183
 
192
184
  // chainable api
193
185
  return this
194
186
 
195
- /**
196
- * This function sets up a new route, its log serializers, and triggers route hooks.
197
- *
198
- * @param {object} opts contains route `path` and `prefixing` flag which indicates if this is an auto-prefixed route, e.g. `fastify.register(routes, { prefix: '/foo' })`
199
- * @param {*} notHandledErr error object to be passed back to the original invoker
200
- * @param {*} done callback
201
- */
202
- function afterRouteAdded ({ path, prefixing = false }, notHandledErr, done) {
187
+ function addNewRoute (path, prefixing = false) {
203
188
  const url = prefix + path
204
189
 
205
190
  opts.url = url
@@ -217,117 +202,122 @@ function buildRouting (options) {
217
202
  }
218
203
 
219
204
  if (prefixing === false) {
220
- // run 'onRoute' hooks
205
+ // run 'onRoute' hooks
221
206
  for (const hook of this[kHooks].onRoute) {
222
- try {
223
- hook.call(this, opts)
224
- } catch (error) {
225
- done(error)
226
- return
227
- }
207
+ hook.call(this, opts)
228
208
  }
229
209
  }
230
210
 
211
+ const constraints = opts.constraints || {}
231
212
  const config = {
232
213
  ...opts.config,
233
214
  url,
234
215
  method: opts.method
235
216
  }
236
- const constraints = opts.constraints || {}
217
+
218
+ const context = new Context({
219
+ schema: opts.schema,
220
+ handler: opts.handler.bind(this),
221
+ config,
222
+ errorHandler: opts.errorHandler,
223
+ bodyLimit: opts.bodyLimit,
224
+ logLevel: opts.logLevel,
225
+ logSerializers: opts.logSerializers,
226
+ attachValidation: opts.attachValidation,
227
+ schemaErrorFormatter: opts.schemaErrorFormatter,
228
+ replySerializer: this[kReplySerializerDefault],
229
+ server: this
230
+ })
231
+
237
232
  if (opts.version) {
238
233
  warning.emit('FSTDEP008')
239
234
  constraints.version = opts.version
240
235
  }
241
236
 
242
- const context = new Context(
243
- opts.schema,
244
- opts.handler.bind(this),
245
- this[kReply],
246
- this[kRequest],
247
- this[kContentTypeParser],
248
- config,
249
- opts.errorHandler || this[kErrorHandler],
250
- opts.bodyLimit,
251
- opts.logLevel,
252
- opts.logSerializers,
253
- opts.attachValidation,
254
- this[kReplySerializerDefault],
255
- opts.schemaErrorFormatter || this[kSchemaErrorFormatter]
256
- )
237
+ const headRouteExists = opts.method === 'HEAD' && router.find(opts.method, opts.url, constraints) != null
257
238
 
258
- const headRouteExists = router.find('HEAD', url, constraints) != null
239
+ // Check if the current route is not for a sibling HEAD one
240
+ if (!headRouteExists) {
241
+ try {
242
+ router.on(opts.method, opts.url, { constraints }, routeHandler, context)
243
+ } catch (error) {
244
+ const isDuplicatedRoute = error.message.includes(`Method '${opts.method}' already declared for route '${opts.url}'`)
245
+ if (isDuplicatedRoute) {
246
+ throw new FST_ERR_DUPLICATED_ROUTE(opts.method, opts.url)
247
+ }
259
248
 
260
- try {
261
- router.on(opts.method, opts.url, { constraints }, routeHandler, context)
262
- } catch (err) {
263
- done(err)
264
- return
249
+ throw error
250
+ }
265
251
  }
266
252
 
267
- const { exposeHeadRoute } = opts
268
- const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
269
- const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
253
+ this.after((notHandledErr, done) => {
254
+ // Send context async
255
+ context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
256
+ context._parserOptions.limit = opts.bodyLimit || null
257
+ context.logLevel = opts.logLevel
258
+ context.logSerializers = opts.logSerializers
259
+ context.attachValidation = opts.attachValidation
260
+ context[kReplySerializerDefault] = this[kReplySerializerDefault]
261
+ context.schemaErrorFormatter = opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
262
+
263
+ // Run hooks and more
264
+ avvio.once('preReady', () => {
265
+ for (const hook of lifecycleHooks) {
266
+ const toSet = this[kHooks][hook]
267
+ .concat(opts[hook] || [])
268
+ .map(h => h.bind(this))
269
+ context[hook] = toSet.length ? toSet : null
270
+ }
270
271
 
271
- if (shouldExposeHead && options.method === 'GET' && !headRouteExists) {
272
- const onSendHandlers = parseHeadOnSendHandlers(opts.onSend)
273
- prepareRoute.call(this, 'HEAD', path, { ...opts, onSend: onSendHandlers })
274
- } else if (headRouteExists && exposeHeadRoute) {
275
- warning.emit('FSTDEP007')
276
- }
272
+ // Optimization: avoid encapsulation if no decoration has been done.
273
+ while (!context.Request[kHasBeenDecorated] && context.Request.parent) {
274
+ context.Request = context.Request.parent
275
+ }
276
+ while (!context.Reply[kHasBeenDecorated] && context.Reply.parent) {
277
+ context.Reply = context.Reply.parent
278
+ }
277
279
 
278
- // It can happen that a user registers a plugin with some hooks *after*
279
- // the route registration. To be sure to also load those hooks,
280
- // we must listen for the avvio's preReady event, and update the context object accordingly.
281
- avvio.once('preReady', () => {
282
- for (const hook of lifecycleHooks) {
283
- const toSet = this[kHooks][hook]
284
- .concat(opts[hook] || [])
285
- .map(h => {
286
- const bound = h.bind(this)
287
-
288
- // Track hooks deprecation markers
289
- if (hook === 'preParsing') {
290
- // Check for deprecation syntax
291
- if (h.length === (h.constructor.name === 'AsyncFunction' ? 2 : 3)) {
292
- warning.emit('FSTDEP004')
293
- bound[kHooksDeprecatedPreParsing] = true
294
- }
295
- }
296
-
297
- return bound
298
- })
299
- context[hook] = toSet.length ? toSet : null
300
- }
280
+ // Must store the 404 Context in 'preReady' because it is only guaranteed to
281
+ // be available after all of the plugins and routes have been loaded.
282
+ fourOhFour.setContext(this, context)
301
283
 
302
- // Must store the 404 Context in 'preReady' because it is only guaranteed to
303
- // be available after all of the plugins and routes have been loaded.
304
- fourOhFour.setContext(this, context)
284
+ if (opts.schema) {
285
+ context.schema = normalizeSchema(context.schema, this.initialConfig)
305
286
 
306
- if (opts.schema) {
307
- context.schema = normalizeSchema(context.schema, this.initialConfig)
287
+ const schemaController = this[kSchemaController]
288
+ if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
289
+ schemaController.setupValidator(this[kOptions])
290
+ }
291
+ try {
292
+ compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler)
293
+ } catch (error) {
294
+ throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
295
+ }
308
296
 
309
- const schemaController = this[kSchemaController]
310
- if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
311
- schemaController.setupValidator(this[kOptions])
312
- }
313
- try {
314
- compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler)
315
- } catch (error) {
316
- throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
297
+ if (opts.schema.response && !opts.serializerCompiler) {
298
+ schemaController.setupSerializer(this[kOptions])
299
+ }
300
+ try {
301
+ compileSchemasForSerialization(context, opts.serializerCompiler || schemaController.serializerCompiler)
302
+ } catch (error) {
303
+ throw new FST_ERR_SCH_SERIALIZATION_BUILD(opts.method, url, error.message)
304
+ }
317
305
  }
306
+ })
318
307
 
319
- if (opts.schema.response && !opts.serializerCompiler) {
320
- schemaController.setupSerializer(this[kOptions])
321
- }
322
- try {
323
- compileSchemasForSerialization(context, opts.serializerCompiler || schemaController.serializerCompiler)
324
- } catch (error) {
325
- throw new FST_ERR_SCH_SERIALIZATION_BUILD(opts.method, url, error.message)
326
- }
308
+ const { exposeHeadRoute } = opts
309
+ const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
310
+ const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
311
+
312
+ if (shouldExposeHead && options.method === 'GET' && !headRouteExists) {
313
+ const onSendHandlers = parseHeadOnSendHandlers(opts.onSend)
314
+ prepareRoute.call(this, 'HEAD', path, { ...opts, onSend: onSendHandlers })
315
+ } else if (headRouteExists && exposeHeadRoute) {
316
+ warning.emit('FSTDEP007')
327
317
  }
328
- })
329
318
 
330
- done(notHandledErr)
319
+ done(notHandledErr)
320
+ })
331
321
  }
332
322
  }
333
323
 
@@ -429,6 +419,16 @@ function handleTimeout () {
429
419
  )
430
420
  }
431
421
 
422
+ function validateMethodAndSchemaBodyOption (method, path, schema) {
423
+ if (supportedMethods.indexOf(method) === -1) {
424
+ throw new Error(`${method} method is not supported!`)
425
+ }
426
+
427
+ if ((method === 'GET' || method === 'HEAD') && schema && schema.body) {
428
+ throw new Error(`Body validation schema for ${method}:${path} route is not supported!`)
429
+ }
430
+ }
431
+
432
432
  function validateBodyLimitOption (bodyLimit) {
433
433
  if (bodyLimit === undefined) return
434
434
  if (!Number.isInteger(bodyLimit) || bodyLimit <= 0) {
@@ -439,6 +439,7 @@ function validateBodyLimitOption (bodyLimit) {
439
439
  function runPreParsing (err, request, reply) {
440
440
  if (reply.sent === true) return
441
441
  if (err != null) {
442
+ reply[kReplyIsError] = true
442
443
  reply.send(err)
443
444
  return
444
445
  }
@@ -465,10 +466,6 @@ function preParsingHookRunner (functions, request, reply, cb) {
465
466
  }
466
467
 
467
468
  if (err || i === functions.length) {
468
- if (err && !(err instanceof Error)) {
469
- reply[kReplyIsError] = true
470
- }
471
-
472
469
  cb(err, request, reply)
473
470
  return
474
471
  }
@@ -476,11 +473,7 @@ function preParsingHookRunner (functions, request, reply, cb) {
476
473
  const fn = functions[i++]
477
474
  let result
478
475
  try {
479
- if (fn[kHooksDeprecatedPreParsing]) {
480
- result = fn(request, reply, next)
481
- } else {
482
- result = fn(request, reply, request[kRequestPayloadStream], next)
483
- }
476
+ result = fn(request, reply, request[kRequestPayloadStream], next)
484
477
  } catch (error) {
485
478
  next(error)
486
479
  return
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { buildSchemas } = require('./schemas')
4
- const { serializerCompiler } = require('./schema-compilers')
4
+ const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
5
5
  const ValidatorSelector = require('@fastify/ajv-compiler')
6
6
 
7
7
  /**
@@ -17,7 +17,7 @@ function buildSchemaController (parentSchemaCtrl, opts) {
17
17
 
18
18
  let compilersFactory = {
19
19
  buildValidator: ValidatorSelector(),
20
- buildSerializer: serializerCompiler
20
+ buildSerializer: SerializerSelector()
21
21
  }
22
22
  if (opts && opts.compilersFactory) {
23
23
  compilersFactory = Object.assign(compilersFactory, opts.compilersFactory)
package/lib/schemas.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const fastClone = require('rfdc')({ circles: false, proto: true })
4
- const { kSchemaVisited } = require('./symbols')
4
+ const { kSchemaVisited, kSchemaResponse } = require('./symbols')
5
5
  const kFluentSchema = Symbol.for('fluent-schema-object')
6
6
 
7
7
  const {
@@ -121,7 +121,33 @@ function getSchemaAnyway (schema, jsonShorthand) {
121
121
  return schema
122
122
  }
123
123
 
124
+ /**
125
+ * Search for the right JSON schema compiled function in the request context
126
+ * setup by the route configuration `schema.response`.
127
+ * It will look for the exact match (eg 200) or generic (eg 2xx)
128
+ *
129
+ * @param {object} context the request context
130
+ * @param {number} statusCode the http status code
131
+ * @returns {function|boolean} the right JSON Schema function to serialize
132
+ * the reply or false if it is not set
133
+ */
134
+ function getSchemaSerializer (context, statusCode) {
135
+ const responseSchemaDef = context[kSchemaResponse]
136
+ if (!responseSchemaDef) {
137
+ return false
138
+ }
139
+ if (responseSchemaDef[statusCode]) {
140
+ return responseSchemaDef[statusCode]
141
+ }
142
+ const fallbackStatusCode = (statusCode + '')[0] + 'xx'
143
+ if (responseSchemaDef[fallbackStatusCode]) {
144
+ return responseSchemaDef[fallbackStatusCode]
145
+ }
146
+ return false
147
+ }
148
+
124
149
  module.exports = {
125
150
  buildSchemas (initStore) { return new Schemas(initStore) },
151
+ getSchemaSerializer,
126
152
  normalizeSchema
127
153
  }