fastify 3.19.0 → 3.20.1

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.
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">Fastify</h1>
2
2
 
3
3
  ## `Content-Type` Parser
4
- Natively, Fastify only supports `'application/json'` and `'text/plain'` content types. The default charset is `utf-8`. If you need to support different content types, you can use the `addContentTypeParser` API. *The default JSON and/or plain text parser can be changed.*
4
+ Natively, Fastify only supports `'application/json'` and `'text/plain'` content types. The default charset is `utf-8`. If you need to support different content types, you can use the `addContentTypeParser` API. *The default JSON and/or plain text parser can be changed or removed.*
5
5
 
6
6
  *Note: If you decide to specify your own content type with the `Content-Type` header, UTF-8 will not be the default. Be sure to include UTF-8 like this `text/html; charset=utf-8`.*
7
7
 
@@ -56,7 +56,11 @@ fastify.addContentTypeParser('application/vnd.custom', (request, body, done) =>
56
56
  fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
57
57
  ```
58
58
 
59
- You can also use the `hasContentTypeParser` API to find if a specific content type parser already exists.
59
+ Besides the `addContentTypeParser` API there are further APIs that can be used. These are `hasContentTypeParser`, `removeContentTypeParser` and `removeAllContentTypeParsers`.
60
+
61
+ #### hasContentTypeParser
62
+
63
+ You can use the `hasContentTypeParser` API to find if a specific content type parser already exists.
60
64
 
61
65
  ```js
62
66
  if (!fastify.hasContentTypeParser('application/jsoff')){
@@ -68,6 +72,40 @@ if (!fastify.hasContentTypeParser('application/jsoff')){
68
72
  }
69
73
  ```
70
74
 
75
+ #### removeContentTypeParser
76
+
77
+ With `removeContentTypeParser` a single or an array of content types can be removed. The method supports `string` and
78
+ `RegExp` content types.
79
+
80
+ ```js
81
+ fastify.addContentTypeParser('text/xml', function (request, payload, done) {
82
+ xmlParser(payload, function (err, body) {
83
+ done(err, body)
84
+ })
85
+ })
86
+
87
+ // Removes the both built-in content type parsers so that only the content type parser for text/html is available
88
+ fastiy.removeContentTypeParser(['application/json', 'text/plain'])
89
+ ```
90
+
91
+ #### removeAllContentTypeParsers
92
+
93
+ In the example from just above, it is noticeable that we need to specify each content type that we want to remove.
94
+ To solve this problem Fastify provides the `removeAllContentTypeParsers` API. This can be used to remove all currently existing content type parsers.
95
+ In the example below we achieve exactly the same as in the example above except that we do not need to specify each content type to delete.
96
+ Just like `removeContentTypeParser`, this API supports encapsulation. The API is especially useful if you want to register a
97
+ [catch-all content type parser](#Catch-All) that should be executed for every content type and the built-in parsers should be ignored as well.
98
+
99
+ ```js
100
+ fastiy.removeAllContentTypeParsers()
101
+
102
+ fastify.addContentTypeParser('text/xml', function (request, payload, done) {
103
+ xmlParser(payload, function (err, body) {
104
+ done(err, body)
105
+ })
106
+ })
107
+ ```
108
+
71
109
  **Notice**: The old syntaxes `function(req, done)` and `async function(req)` for the parser are still supported but they are deprecated.
72
110
 
73
111
  #### Body Parser
@@ -140,3 +178,19 @@ fastify.route({
140
178
  ```
141
179
 
142
180
  For piping file uploads you may want to check out [this plugin](https://github.com/fastify/fastify-multipart).
181
+
182
+ If you really want the content type parser to be executed on all content types and not only on those that don't have a
183
+ specific one, you should call the `removeAllContentTypeParsers` method first.
184
+
185
+ ```js
186
+ // Without this call, the request body with the content type application/json would be processed by the built in json parser
187
+ fastify.removeAllContentTypeParsers()
188
+
189
+ fastify.addContentTypeParser('*', function (request, payload, done) {
190
+ var data = ''
191
+ payload.on('data', chunk => { data += chunk })
192
+ payload.on('end', () => {
193
+ done(null, data)
194
+ })
195
+ })
196
+ ```
@@ -117,6 +117,9 @@ upon "greet" and "log" decorators:
117
117
  fastify.decorate('utility', fn, ['greet', 'log'])
118
118
  ```
119
119
 
120
+ Note: using an arrow function will break the binding of `this` to the
121
+ `FastifyInstance`.
122
+
120
123
  If a dependency is not satisfied, the `decorate` method will throw an exception.
121
124
  The dependency check is performed before the server instance is booted. Thus,
122
125
  it cannot occur during runtime.
package/docs/Ecosystem.md CHANGED
@@ -102,6 +102,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
102
102
  - [`fastify-file-upload`](https://github.com/huangang/fastify-file-upload) Fastify plugin for uploading files.
103
103
  - [`fastify-firebase`](https://github.com/now-ims/fastify-firebase) Fastify plugin for [Firebase Admin SDK](https://firebase.google.com/docs/admin/setup) to Fastify so you can easily use Firebase Auth, Firestore, Cloud Storage, Cloud Messaging, and more.
104
104
  - [`fastify-firebase-auth`](https://github.com/oxsav/fastify-firebase-auth) Firebase Authentication for Fastify supporting all of the methods relating to the authentication API.
105
+ - [`fastify-formidable`](https://github.com/climba03003/fastify-formidable) Handy plugin to provide multipart support and fastify-swagger integration.
105
106
  - [`fastify-gcloud-trace`](https://github.com/mkinoshi/fastify-gcloud-trace) [Google Cloud Trace API](https://cloud.google.com/trace/docs/reference) Connector for Fastify.
106
107
  - [`fastify-get-head`](https://github.com/MetCoder95/fastify-get-head) Small plugin to set a new HEAD route handler for each GET route previously registered in Fastify.
107
108
  - [`fastify-good-sessions`](https://github.com/Phara0h/fastify-good-sessions) A good Fastify sessions plugin focused on speed.
@@ -161,6 +162,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
161
162
  - [`fastify-qs`](https://github.com/webdevium/fastify-qs) A plugin for Fastify that adds support for parsing URL query parameters with [qs](https://github.com/ljharb/qs).
162
163
  - [`fastify-raw-body`](https://github.com/Eomm/fastify-raw-body) Add the `request.rawBody` field.
163
164
  - [`fastify-rbac`](https://gitlab.com/m03geek/fastify-rbac) Fastify role-based access control plugin.
165
+ - [`fastify-recaptcha`](https://github.com/qwertyforce/fastify-recaptcha) Fastify plugin for recaptcha verification.
164
166
  - [`fastify-redis-channels`](https://github.com/hearit-io/fastify-redis-channels) A plugin for fast, reliable, and scalable channels implementation based on Redis streams.
165
167
  - [`fastify-register-routes`](https://github.com/israeleriston/fastify-register-routes) Plugin to automatically load routes from a specified path and optionally limit loaded file names by a regular expression.
166
168
  - [`fastify-response-time`](https://github.com/lolo32/fastify-response-time) Add `X-Response-Time` header at each request for Fastify, in milliseconds.
@@ -168,6 +170,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
168
170
  - [`fastify-resty`](https://github.com/FastifyResty/fastify-resty) Fastify-based web framework with REST API routes auto-generation for TypeORM entities using DI and decorators.
169
171
  - [`fastify-reverse-routes`](https://github.com/dimonnwc3/fastify-reverse-routes) Fastify reverse routes plugin, allows to defined named routes and build path using name and parameters.
170
172
  - [`fastify-rob-config`](https://github.com/jeromemacias/fastify-rob-config) Fastify Rob-Config integration.
173
+ - [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group) Convenient grouping and inheritance of routes
171
174
  - [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint) Choose the JSON schema to use based on request parameters.
172
175
  - [`fastify-schema-to-typescript`](https://github.com/thomasthiebaud/fastify-schema-to-typescript) Generate typescript types based on your JSON/YAML validation schemas so they are always in sync.
173
176
  - [`fastify-secure-session`](https://github.com/mcollina/fastify-secure-session) Create a secure stateless cookie session for Fastify.
@@ -175,6 +178,7 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
175
178
  - [`fastify-sequelize`](https://github.com/lyquocnam/fastify-sequelize) Fastify plugin work with Sequelize (adapter for NodeJS -> Sqlite, Mysql, Mssql, Postgres).
176
179
  - [`fastify-server-session`](https://github.com/jsumners/fastify-server-session) A session plugin with support for arbitrary backing caches via `fastify-caching`.
177
180
  - [`fastify-session`](https://github.com/SerayaEryn/fastify-session) a session plugin for Fastify.
181
+ - [`fastify-slonik`](https://github.com/Unbuttun/fastify-slonik) Fastify Slonik plugin, with this you can use slonik in every part of your server.
178
182
  - [`fastify-soap-client`](https://github.com/fastify/fastify-soap-client) a SOAP client plugin for Fastify.
179
183
  - [`fastify-socket.io`](https://github.com/alemagio/fastify-socket.io) a Socket.io plugin for Fastify.
180
184
  - [`fastify-sse`](https://github.com/lolo32/fastify-sse) to provide Server-Sent Events with `reply.sse( … )` to Fastify.
@@ -200,4 +204,4 @@ Plugins maintained by the Fastify team are listed under [Core](#core) while plug
200
204
  - [`nstats`](https://github.com/Phara0h/nstats) A fast and compact way to get all your network and process stats for your node application. Websocket, HTTP/S, and prometheus compatible!
201
205
  - [`oas-fastify`](https://github.com/ahmadnassri/node-oas-fastify) OAS 3.x to Fastify routes automation. Automatically generates route handlers with fastify configuration and validation.
202
206
  - [`openapi-validator-middleware`](https://github.com/PayU/openapi-validator-middleware#fastify) Swagger and OpenAPI 3.0 spec-based request validation middleware that supports Fastify.
203
- - [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group) Convenient grouping and inheritance of routes
207
+ - [`sequelize-fastify`](https://github.com/hsynlms/sequelize-fastify) A simple and lightweight Sequelize plugin for Fastify.
@@ -184,7 +184,7 @@ async function routes (fastify, options) {
184
184
 
185
185
  fastify.get('/animals/:animal', async (request, reply) => {
186
186
  const result = await collection.findOne({ animal: request.params.animal })
187
- if (result === null) {
187
+ if (!result) {
188
188
  throw new Error('Invalid value')
189
189
  }
190
190
  return result
package/docs/Reply.md CHANGED
@@ -53,10 +53,11 @@ and properties:
53
53
  - `.serializer(function)` - Sets a custom serializer for the payload.
54
54
  - `.send(payload)` - Sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object.
55
55
  - `.sent` - A boolean value that you can use if you need to know if `send` has already been called.
56
- - `.raw` - The [`http.ServerResponse`](https://nodejs.org/dist/latest/docs/api/http.html#http_class_http_serverresponse) from Node core.
57
- - `.res` *(deprecated, use `.raw` instead)* - The [`http.ServerResponse`](https://nodejs.org/dist/latest/docs/api/http.html#http_class_http_serverresponse) from Node core.
56
+ - `.raw` - The [`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse) from Node core.
57
+ - `.res` *(deprecated, use `.raw` instead)* - The [`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse) from Node core.
58
58
  - `.log` - The logger instance of the incoming request.
59
59
  - `.request` - The incoming request.
60
+ - `.context` - Access the [Request's context](Request.md#Request) property.
60
61
 
61
62
  ```js
62
63
  fastify.get('/', options, function (request, reply) {
@@ -108,7 +109,7 @@ fastify.get('/', async function (req, rep) {
108
109
  Sets a response header. If the value is omitted or undefined, it is coerced
109
110
  to `''`.
110
111
 
111
- For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest/docs/api/http.html#http_response_setheader_name_value).
112
+ For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_response_setheader_name_value).
112
113
 
113
114
  <a name="headers"></a>
114
115
  ### .headers(object)
@@ -227,7 +228,7 @@ See [`.send()`](#send) for more information on sending different types of values
227
228
 
228
229
  <a name="raw"></a>
229
230
  ### .raw
230
- This is the [`http.ServerResponse`](https://nodejs.org/dist/latest/docs/api/http.html#http_class_http_serverresponse) from Node core. Whilst you are using the Fastify `Reply` object, the use of `Reply.raw` functions is at your own risk as you are skipping all the Fastify
231
+ This is the [`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse) from Node core. Whilst you are using the Fastify `Reply` object, the use of `Reply.raw` functions is at your own risk as you are skipping all the Fastify
231
232
  logic of handling the HTTP response. e.g.:
232
233
 
233
234
  ```js
@@ -300,7 +301,7 @@ fastify.get('/json', options, function (request, reply) {
300
301
 
301
302
  <a name="send-streams"></a>
302
303
  #### Streams
303
- *send* can also handle streams out of the box, internally uses [pump](https://www.npmjs.com/package/pump) to avoid leaks of file descriptors. If you are sending a stream and you have not set a `'Content-Type'` header, *send* will set it at `'application/octet-stream'`.
304
+ *send* can also handle streams out of the box. If you are sending a stream and you have not set a `'Content-Type'` header, *send* will set it at `'application/octet-stream'`.
304
305
  ```js
305
306
  fastify.get('/streams', function (request, reply) {
306
307
  const fs = require('fs')
package/docs/Request.md CHANGED
@@ -23,6 +23,8 @@ Request is a core Fastify object containing the following fields:
23
23
  - `is404` - true if request is being handled by 404 handler, false if it is not
24
24
  - `connection` - Deprecated, use `socket` instead. The underlying connection of the incoming request.
25
25
  - `socket` - the underlying connection of the incoming request
26
+ - `context` - A Fastify internal object. You should not use it directly or modify it. It is usefull to access one special key:
27
+ - `context.config` - The route [`config`](Routes.md#routes-config) object.
26
28
 
27
29
 
28
30
  ```js
package/docs/Routes.md CHANGED
@@ -427,7 +427,7 @@ Fastify will require a request `Accept-Version` header to be set if the route ha
427
427
  fastify.route({
428
428
  method: 'GET',
429
429
  url: '/',
430
- { constraints: { version: '1.2.0'} },
430
+ constraints: { version: '1.2.0' },
431
431
  handler: function (request, reply) {
432
432
  reply.send({ hello: 'world' })
433
433
  }
@@ -475,7 +475,7 @@ You can provide a `host` key in the `constraints` route option for to limit that
475
475
  fastify.route({
476
476
  method: 'GET',
477
477
  url: '/',
478
- { constraints: { host: 'auth.fastify.io' } },
478
+ constraints: { host: 'auth.fastify.io' },
479
479
  handler: function (request, reply) {
480
480
  reply.send('hello world from auth.fastify.io')
481
481
  }
@@ -508,7 +508,7 @@ RegExp `host` constraints can also be specified allowing constraining to hosts m
508
508
  fastify.route({
509
509
  method: 'GET',
510
510
  url: '/',
511
- { constraints: { host: /.*\.fastify\.io/ } }, // will match any subdomain of fastify.io
511
+ constraints: { host: /.*\.fastify\.io/ }, // will match any subdomain of fastify.io
512
512
  handler: function (request, reply) {
513
513
  reply.send('hello world from ' + request.headers.host)
514
514
  }
package/docs/Server.md CHANGED
@@ -11,7 +11,7 @@ document describes the properties available in that options object.
11
11
  <a name="factory-http2"></a>
12
12
  ### `http2`
13
13
 
14
- If `true` Node.js core's [HTTP/2](https://nodejs.org/dist/latest-v8.x/docs/api/http2.html) module is used for binding the socket.
14
+ If `true` Node.js core's [HTTP/2](https://nodejs.org/dist/latest-v14.x/docs/api/http2.html) module is used for binding the socket.
15
15
 
16
16
  + Default: `false`
17
17
 
@@ -20,7 +20,7 @@ If `true` Node.js core's [HTTP/2](https://nodejs.org/dist/latest-v8.x/docs/api/h
20
20
 
21
21
  An object used to configure the server's listening socket for TLS. The options
22
22
  are the same as the Node.js core
23
- [`createServer` method](https://nodejs.org/dist/latest-v8.x/docs/api/https.html#https_https_createserver_options_requestlistener).
23
+ [`createServer` method](https://nodejs.org/dist/latest-v14.x/docs/api/https.html#https_https_createserver_options_requestlistener).
24
24
  When this property is `null`, the socket will not be configured for TLS.
25
25
 
26
26
  This option also applies when the
@@ -113,7 +113,7 @@ for more details about prototype poisoning attacks.
113
113
 
114
114
  Possible values are `'error'`, `'remove'` and `'ignore'`.
115
115
 
116
- + Default: `'ignore'`
116
+ + Default: `'error'`
117
117
 
118
118
  <a name="factory-logger"></a>
119
119
  ### `logger`
@@ -454,8 +454,10 @@ const fastify = require('fastify')({
454
454
  Set a default
455
455
  [timeout](https://nodejs.org/api/http2.html#http2_http2session_settimeout_msecs_callback) to every incoming HTTP/2 session. The session will be closed on the timeout. Default: `5000` ms.
456
456
 
457
- Note that this is needed to offer the graceful "close" experience when
458
- using HTTP/2. Node core defaults this to `0`.
457
+ Note that this is needed to offer the graceful "close" experience when using HTTP/2.
458
+ The low default has been chosen to mitigate denial of service attacks.
459
+ When the server is behind a load balancer or can scale automatically this value can be
460
+ increased to fit the use case. Node core defaults this to `0`. `
459
461
 
460
462
  <a name="framework-errors"></a>
461
463
  ### `frameworkErrors`
@@ -164,7 +164,7 @@ When you want to use it for validation of some payload in a fastify route you ca
164
164
  ```typescript
165
165
  const app = fastify();
166
166
 
167
- app.post<{ Body: UserType; Response: UserType }>(
167
+ app.post<{ Body: UserType; Reply: UserType }>(
168
168
  "/",
169
169
  {
170
170
  schema: {
package/fastify.d.ts CHANGED
@@ -14,6 +14,7 @@ import { FastifyReply } from './types/reply'
14
14
  import { FastifySchemaValidationError } from './types/schema'
15
15
  import { ConstructorAction, ProtoAction } from "./types/content-type-parser";
16
16
  import { Socket } from 'net'
17
+ import { Options as FJSOptions } from 'fast-json-stringify'
17
18
 
18
19
  /**
19
20
  * Fastify factory function for the standard fastify http, https, or http2 server instance.
@@ -102,6 +103,7 @@ export type FastifyServerOptions<
102
103
  onProtoPoisoning?: ProtoAction,
103
104
  onConstructorPoisoning?: ConstructorAction,
104
105
  logger?: boolean | FastifyLoggerOptions<RawServer> | Logger,
106
+ serializerOpts?: FJSOptions | Record<string, unknown>,
105
107
  serverFactory?: FastifyServerFactory<RawServer>,
106
108
  caseSensitive?: boolean,
107
109
  requestIdHeader?: string,
@@ -122,7 +124,7 @@ export type FastifyServerOptions<
122
124
  deriveVersion<Context>(req: Object, ctx?: Context): string // not a fan of using Object here. Also what is Context? Can either of these be better defined?
123
125
  },
124
126
  constraints?: {
125
- [name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>>,
127
+ [name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>,
126
128
  },
127
129
  return503OnClosing?: boolean,
128
130
  ajv?: {
@@ -163,7 +165,7 @@ export type { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRe
163
165
  export { FastifyRequest, RequestGenericInterface } from './types/request'
164
166
  export { FastifyReply } from './types/reply'
165
167
  export { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
166
- export { FastifyInstance } from './types/instance'
168
+ export { FastifyInstance, PrintRoutesOptions } from './types/instance'
167
169
  export { FastifyLoggerOptions, FastifyLoggerInstance, FastifyLogFn, LogLevel } from './types/logger'
168
170
  export { FastifyContext, FastifyContextConfig } from './types/context'
169
171
  export { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
package/fastify.js CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  const Avvio = require('avvio')
4
4
  const http = require('http')
5
- const path = require('path')
6
5
  const querystring = require('querystring')
7
6
  let lightMyRequest
7
+ let version
8
+ let versionLoaded = false
8
9
 
9
- const { version } = require(path.join(__dirname, 'package.json'))
10
10
  const {
11
11
  kAvvioBoot,
12
12
  kChildren,
@@ -272,6 +272,8 @@ function fastify (options) {
272
272
  hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser,
273
273
  getDefaultJsonParser: ContentTypeParser.defaultParsers.getDefaultJsonParser,
274
274
  defaultTextParser: ContentTypeParser.defaultParsers.defaultTextParser,
275
+ removeContentTypeParser: ContentTypeParser.helpers.removeContentTypeParser,
276
+ removeAllContentTypeParsers: ContentTypeParser.helpers.removeAllContentTypeParsers,
275
277
  // Fastify architecture methods (initialized by Avvio)
276
278
  register: null,
277
279
  after: null,
@@ -323,6 +325,9 @@ function fastify (options) {
323
325
  },
324
326
  version: {
325
327
  get () {
328
+ if (versionLoaded === false) {
329
+ version = loadVersion()
330
+ }
326
331
  return version
327
332
  }
328
333
  },
@@ -672,6 +677,20 @@ function wrapRouting (httpHandler, { rewriteUrl, logger }) {
672
677
  }
673
678
  }
674
679
 
680
+ function loadVersion () {
681
+ versionLoaded = true
682
+ const fs = require('fs')
683
+ const path = require('path')
684
+ try {
685
+ const pkgPath = path.join(__dirname, 'package.json')
686
+ fs.accessSync(pkgPath, fs.constants.R_OK)
687
+ const pkg = JSON.parse(fs.readFileSync(pkgPath))
688
+ return pkg.name === 'fastify' ? pkg.version : undefined
689
+ } catch (e) {
690
+ return undefined
691
+ }
692
+ }
693
+
675
694
  /**
676
695
  * These export configurations enable JS and TS developers
677
696
  * to consumer fastify in whatever way best suits their needs.
@@ -116,6 +116,27 @@ ContentTypeParser.prototype.getParser = function (contentType) {
116
116
  return this.customParsers['']
117
117
  }
118
118
 
119
+ ContentTypeParser.prototype.removeAll = function () {
120
+ this.customParsers = {}
121
+ this.parserRegExpList = []
122
+ this.parserList = []
123
+ this.cache = lru(100)
124
+ }
125
+
126
+ ContentTypeParser.prototype.remove = function (contentType) {
127
+ if (!(typeof contentType === 'string' || contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
128
+
129
+ delete this.customParsers[contentType]
130
+
131
+ const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList
132
+
133
+ const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
134
+
135
+ if (idx > -1) {
136
+ parsers.splice(idx, 1)
137
+ }
138
+ }
139
+
119
140
  ContentTypeParser.prototype.run = function (contentType, handler, request, reply) {
120
141
  const parser = this.cache.get(contentType) || this.getParser(contentType)
121
142
 
@@ -297,11 +318,35 @@ function hasContentTypeParser (contentType) {
297
318
  return this[kContentTypeParser].hasParser(contentType)
298
319
  }
299
320
 
321
+ function removeContentTypeParser (contentType) {
322
+ if (this[kState].started) {
323
+ throw new Error('Cannot call "removeContentTypeParser" when fastify instance is already started!')
324
+ }
325
+
326
+ if (Array.isArray(contentType)) {
327
+ for (const type of contentType) {
328
+ this[kContentTypeParser].remove(type)
329
+ }
330
+ } else {
331
+ this[kContentTypeParser].remove(contentType)
332
+ }
333
+ }
334
+
335
+ function removeAllContentTypeParsers () {
336
+ if (this[kState].started) {
337
+ throw new Error('Cannot call "removeAllContentTypeParsers" when fastify instance is already started!')
338
+ }
339
+
340
+ this[kContentTypeParser].removeAll()
341
+ }
342
+
300
343
  module.exports = ContentTypeParser
301
344
  module.exports.helpers = {
302
345
  buildContentTypeParser,
303
346
  addContentTypeParser,
304
- hasContentTypeParser
347
+ hasContentTypeParser,
348
+ removeContentTypeParser,
349
+ removeAllContentTypeParsers
305
350
  }
306
351
  module.exports.defaultParsers = {
307
352
  getDefaultJsonParser,
package/lib/logger.js CHANGED
@@ -35,7 +35,7 @@ function createPinoLogger (opts, stream) {
35
35
  if (prevLogger[serializersSym]) {
36
36
  opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
37
37
  }
38
- logger = prevLogger.child(opts)
38
+ logger = prevLogger.child({}, opts)
39
39
  opts.logger = prevLogger
40
40
  opts.genReqId = prevGenReqId
41
41
  } else {
@@ -109,7 +109,9 @@ function registerPluginName (fn) {
109
109
 
110
110
  function registerPlugin (fn) {
111
111
  registerPluginName.call(this, fn)
112
- checkVersion.call(this, fn)
112
+ if (this.version !== undefined) {
113
+ checkVersion.call(this, fn)
114
+ }
113
115
  checkDecorators.call(this, fn)
114
116
  checkDependencies.call(this, fn)
115
117
  return shouldSkipOverride(fn)
package/lib/reply.js CHANGED
@@ -548,8 +548,12 @@ function handleError (reply, error, cb) {
548
548
  reply[kReplyErrorHandlerCalled] = true
549
549
  reply[kReplyHeaders]['content-length'] = undefined
550
550
  const result = errorHandler(error, reply.request, reply)
551
- if (result && typeof result.then === 'function') {
552
- wrapThenable(result, reply)
551
+ if (result !== undefined) {
552
+ if (result !== null && typeof result.then === 'function') {
553
+ wrapThenable(result, reply)
554
+ } else {
555
+ reply.send(result)
556
+ }
553
557
  }
554
558
  return
555
559
  }
package/lib/route.js CHANGED
@@ -247,7 +247,7 @@ function buildRouting (options) {
247
247
  opts.schemaErrorFormatter || this[kSchemaErrorFormatter]
248
248
  )
249
249
 
250
- const headRouteExists = router.find('HEAD', path) != null
250
+ const headRouteExists = router.find('HEAD', url) != null
251
251
 
252
252
  try {
253
253
  router.on(opts.method, opts.url, { constraints }, routeHandler, context)
@@ -345,15 +345,18 @@ function buildRouting (options) {
345
345
 
346
346
  const id = req.headers[requestIdHeader] || genReqId(req)
347
347
 
348
+ const loggerBinding = {
349
+ [requestIdLogLabel]: id
350
+ }
351
+
348
352
  const loggerOpts = {
349
- [requestIdLogLabel]: id,
350
353
  level: context.logLevel
351
354
  }
352
355
 
353
356
  if (context.logSerializers) {
354
357
  loggerOpts.serializers = context.logSerializers
355
358
  }
356
- const childLogger = logger.child(loggerOpts)
359
+ const childLogger = logger.child(loggerBinding, loggerOpts)
357
360
  childLogger[kDisableRequestLogging] = disableRequestLogging
358
361
 
359
362
  const queryPrefix = req.url.indexOf('?')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.19.0",
3
+ "version": "3.20.1",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -164,7 +164,7 @@
164
164
  "tap": "^15.0.5",
165
165
  "tap-mocha-reporter": "^5.0.1",
166
166
  "then-sleep": "^1.0.1",
167
- "tsd": "^0.14.0",
167
+ "tsd": "^0.17.0",
168
168
  "typescript": "^4.0.2",
169
169
  "undici": "^3.3.5",
170
170
  "x-xss-protection": "^2.0.0",
@@ -177,10 +177,10 @@
177
177
  "fast-json-stringify": "^2.5.2",
178
178
  "fastify-error": "^0.3.0",
179
179
  "fastify-warning": "^0.2.0",
180
- "find-my-way": "^4.0.0",
180
+ "find-my-way": "^4.1.0",
181
181
  "flatstr": "^1.0.12",
182
182
  "light-my-request": "^4.2.0",
183
- "pino": "^6.2.1",
183
+ "pino": "^6.13.0",
184
184
  "proxy-addr": "^2.0.7",
185
185
  "readable-stream": "^3.4.0",
186
186
  "rfdc": "^1.1.4",
@@ -646,6 +646,79 @@ test('customErrorHandler only called if reply not already sent', t => {
646
646
  })
647
647
  })
648
648
 
649
+ // See https://github.com/fastify/fastify/issues/3209
650
+ test('setNotFoundHandler should accept return value', t => {
651
+ t.plan(3)
652
+
653
+ const fastify = Fastify()
654
+
655
+ fastify.get('/', async () => ({ hello: 'world' }))
656
+
657
+ fastify.setNotFoundHandler((req, reply) => {
658
+ reply.code(404)
659
+ return {
660
+ error: statusCodes['404'],
661
+ message: 'lost',
662
+ statusCode: 404
663
+ }
664
+ })
665
+
666
+ fastify.inject({
667
+ method: 'GET',
668
+ url: '/elsewhere'
669
+ }, (err, res) => {
670
+ t.error(err)
671
+ t.equal(res.statusCode, 404)
672
+ t.same(
673
+ {
674
+ error: statusCodes['404'],
675
+ message: 'lost',
676
+ statusCode: 404
677
+ },
678
+ JSON.parse(res.payload)
679
+ )
680
+ })
681
+ })
682
+
683
+ // See https://github.com/fastify/fastify/issues/3209
684
+ test('customErrorHandler should accept return value', t => {
685
+ t.plan(4)
686
+
687
+ const fastify = Fastify()
688
+
689
+ fastify.get('/', async (req, reply) => {
690
+ const error = new Error('ouch')
691
+ error.statusCode = 400
692
+ throw error
693
+ })
694
+
695
+ fastify.setErrorHandler((err, req, reply) => {
696
+ t.equal(err.message, 'ouch')
697
+ reply.code(401)
698
+ return {
699
+ error: statusCodes['401'],
700
+ message: 'kaboom',
701
+ statusCode: 401
702
+ }
703
+ })
704
+
705
+ fastify.inject({
706
+ method: 'GET',
707
+ url: '/'
708
+ }, (err, res) => {
709
+ t.error(err)
710
+ t.equal(res.statusCode, 401)
711
+ t.same(
712
+ {
713
+ error: statusCodes['401'],
714
+ message: 'kaboom',
715
+ statusCode: 401
716
+ },
717
+ JSON.parse(res.payload)
718
+ )
719
+ })
720
+ })
721
+
649
722
  test('await self', async t => {
650
723
  const app = Fastify()
651
724
  t.equal(await app, app)