fastify 3.26.0 → 4.0.0-alpha.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.
Files changed (129) hide show
  1. package/README.md +5 -4
  2. package/build/build-error-serializer.js +27 -0
  3. package/build/build-validation.js +49 -35
  4. package/docs/Guides/Ecosystem.md +2 -1
  5. package/docs/Guides/Prototype-Poisoning.md +3 -3
  6. package/docs/Migration-Guide-V4.md +12 -0
  7. package/docs/Reference/ContentTypeParser.md +8 -1
  8. package/docs/Reference/Errors.md +51 -6
  9. package/docs/Reference/Hooks.md +4 -7
  10. package/docs/Reference/LTS.md +5 -4
  11. package/docs/Reference/Reply.md +23 -22
  12. package/docs/Reference/Request.md +1 -3
  13. package/docs/Reference/Routes.md +17 -10
  14. package/docs/Reference/Server.md +98 -63
  15. package/docs/Reference/TypeScript.md +11 -13
  16. package/docs/Reference/Validation-and-Serialization.md +32 -54
  17. package/docs/Type-Providers.md +257 -0
  18. package/examples/hooks.js +1 -1
  19. package/examples/simple-stream.js +18 -0
  20. package/fastify.d.ts +36 -22
  21. package/fastify.js +72 -53
  22. package/lib/configValidator.js +902 -1023
  23. package/lib/contentTypeParser.js +6 -16
  24. package/lib/context.js +36 -10
  25. package/lib/decorate.js +5 -3
  26. package/lib/error-handler.js +158 -0
  27. package/lib/error-serializer.js +257 -0
  28. package/lib/errors.js +49 -10
  29. package/lib/fourOhFour.js +31 -20
  30. package/lib/handleRequest.js +10 -13
  31. package/lib/hooks.js +14 -9
  32. package/lib/noop-set.js +10 -0
  33. package/lib/pluginOverride.js +0 -3
  34. package/lib/pluginUtils.js +3 -2
  35. package/lib/reply.js +44 -163
  36. package/lib/request.js +13 -10
  37. package/lib/route.js +158 -139
  38. package/lib/schema-controller.js +3 -3
  39. package/lib/schemas.js +27 -1
  40. package/lib/server.js +219 -116
  41. package/lib/symbols.js +6 -4
  42. package/lib/validation.js +2 -1
  43. package/lib/warnings.js +2 -12
  44. package/lib/wrapThenable.js +4 -11
  45. package/package.json +40 -45
  46. package/test/404s.test.js +265 -108
  47. package/test/500s.test.js +2 -2
  48. package/test/async-await.test.js +15 -71
  49. package/test/close.test.js +39 -1
  50. package/test/content-parser.test.js +32 -0
  51. package/test/context-config.test.js +56 -4
  52. package/test/custom-http-server.test.js +14 -7
  53. package/test/custom-parser-async.test.js +0 -65
  54. package/test/custom-parser.test.js +54 -121
  55. package/test/decorator.test.js +1 -3
  56. package/test/delete.test.js +5 -5
  57. package/test/encapsulated-error-handler.test.js +50 -0
  58. package/test/esm/index.test.js +0 -14
  59. package/test/fastify-instance.test.js +4 -4
  60. package/test/fluent-schema.test.js +4 -4
  61. package/test/get.test.js +3 -3
  62. package/test/helper.js +18 -3
  63. package/test/hooks-async.test.js +14 -47
  64. package/test/hooks.on-ready.test.js +9 -4
  65. package/test/hooks.test.js +58 -99
  66. package/test/http2/closing.test.js +5 -11
  67. package/test/http2/unknown-http-method.test.js +3 -9
  68. package/test/https/custom-https-server.test.js +12 -6
  69. package/test/inject.test.js +1 -1
  70. package/test/input-validation.js +2 -2
  71. package/test/internals/all.test.js +2 -2
  72. package/test/internals/contentTypeParser.test.js +4 -4
  73. package/test/internals/handleRequest.test.js +9 -46
  74. package/test/internals/initialConfig.test.js +33 -12
  75. package/test/internals/logger.test.js +1 -1
  76. package/test/internals/reply.test.js +245 -3
  77. package/test/internals/request.test.js +13 -7
  78. package/test/internals/server.test.js +88 -0
  79. package/test/listen.test.js +84 -1
  80. package/test/logger.test.js +98 -58
  81. package/test/maxRequestsPerSocket.test.js +8 -6
  82. package/test/middleware.test.js +2 -25
  83. package/test/noop-set.test.js +19 -0
  84. package/test/nullable-validation.test.js +51 -14
  85. package/test/plugin.test.js +31 -5
  86. package/test/pretty-print.test.js +22 -10
  87. package/test/reply-error.test.js +123 -12
  88. package/test/request-error.test.js +2 -5
  89. package/test/route-hooks.test.js +17 -17
  90. package/test/route-prefix.test.js +2 -1
  91. package/test/route.test.js +216 -20
  92. package/test/router-options.test.js +1 -1
  93. package/test/schema-examples.test.js +11 -5
  94. package/test/schema-feature.test.js +24 -19
  95. package/test/schema-serialization.test.js +50 -9
  96. package/test/schema-special-usage.test.js +14 -81
  97. package/test/schema-validation.test.js +9 -9
  98. package/test/skip-reply-send.test.js +8 -8
  99. package/test/stream.test.js +23 -12
  100. package/test/throw.test.js +8 -5
  101. package/test/trust-proxy.test.js +1 -1
  102. package/test/type-provider.test.js +20 -0
  103. package/test/types/fastify.test-d.ts +12 -18
  104. package/test/types/hooks.test-d.ts +7 -3
  105. package/test/types/import.js +2 -0
  106. package/test/types/import.ts +1 -0
  107. package/test/types/instance.test-d.ts +61 -15
  108. package/test/types/logger.test-d.ts +44 -15
  109. package/test/types/route.test-d.ts +8 -2
  110. package/test/types/schema.test-d.ts +2 -39
  111. package/test/types/type-provider.test-d.ts +417 -0
  112. package/test/validation-error-handling.test.js +9 -9
  113. package/test/versioned-routes.test.js +29 -17
  114. package/test/wrapThenable.test.js +7 -6
  115. package/types/.eslintrc.json +1 -1
  116. package/types/content-type-parser.d.ts +17 -8
  117. package/types/hooks.d.ts +107 -60
  118. package/types/instance.d.ts +137 -105
  119. package/types/logger.d.ts +18 -104
  120. package/types/plugin.d.ts +10 -4
  121. package/types/register.d.ts +1 -1
  122. package/types/reply.d.ts +16 -11
  123. package/types/request.d.ts +10 -5
  124. package/types/route.d.ts +42 -31
  125. package/types/schema.d.ts +15 -1
  126. package/types/type-provider.d.ts +99 -0
  127. package/types/utils.d.ts +1 -1
  128. package/lib/schema-compilers.js +0 -12
  129. package/test/emit-warning.test.js +0 -166
package/README.md CHANGED
@@ -1,5 +1,4 @@
1
- <div align="center">
2
- <a href="https://fastify.io/">
1
+ <div align="center"> <a href="https://fastify.io/">
3
2
  <img src="https://github.com/fastify/graphics/raw/HEAD/fastify-landscape-outlined.svg" width="650" height="auto"/>
4
3
  </a>
5
4
  </div>
@@ -45,6 +44,8 @@ How can you efficiently handle the resources of your server, knowing that you ar
45
44
 
46
45
  Enter Fastify. Fastify is a web framework highly focused on providing the best developer experience with the least overhead and a powerful plugin architecture. It is inspired by Hapi and Express and as far as we know, it is one of the fastest web frameworks in town.
47
46
 
47
+ This branch refers to the upcoming Fastify v4 release. Check out the [v3.x](https://github.com/fastify/fastify/tree/v3.x) branch for v3.
48
+
48
49
  ### Quick start
49
50
 
50
51
  Create a folder and make it your current working directory:
@@ -88,11 +89,11 @@ If installing in an existing project, then Fastify can be installed into the pro
88
89
 
89
90
  Install with npm:
90
91
  ```sh
91
- npm i fastify --save
92
+ npm i fastify@next --save
92
93
  ```
93
94
  Install with yarn:
94
95
  ```sh
95
- yarn add fastify
96
+ yarn add fastify@next
96
97
  ```
97
98
 
98
99
  ### Example
@@ -0,0 +1,27 @@
1
+ 'use strict'
2
+
3
+ const FJS = require('fast-json-stringify')
4
+ const path = require('path')
5
+ const fs = require('fs')
6
+
7
+ const debugCompiled = FJS({
8
+ type: 'object',
9
+ properties: {
10
+ statusCode: { type: 'number' },
11
+ code: { type: 'string' },
12
+ error: { type: 'string' },
13
+ message: { type: 'string' }
14
+ }
15
+ }, { debugMode: true })
16
+
17
+ const file = path.join(__dirname, '..', 'lib', 'error-serializer.js')
18
+ const rawString = debugCompiled.toString()
19
+
20
+ const moduleCode = `// This file is autogenerated by build/build-error-serializer.js, do not edit
21
+ /* istanbul ignore file */
22
+ module.exports = $main
23
+ ${rawString.slice(5)}
24
+ `
25
+
26
+ fs.writeFileSync(file, moduleCode)
27
+ console.log(`Saved ${file} file successfully`)
@@ -1,20 +1,30 @@
1
1
  'use strict'
2
2
 
3
- const Ajv = require('ajv')
3
+ const AjvStandaloneCompiler = require('@fastify/ajv-compiler/standalone')
4
+ const { _ } = require('ajv')
4
5
  const fs = require('fs')
5
6
  const path = require('path')
6
- const pack = require('ajv-pack')
7
7
 
8
- const ajv = new Ajv({
9
- sourceCode: true, // this option is required by ajv-pack
10
- removeAdditional: true,
11
- useDefaults: true,
12
- coerceTypes: true
8
+ const factory = AjvStandaloneCompiler({
9
+ readMode: false,
10
+ storeFunction (routeOpts, schemaValidationCode) {
11
+ const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
12
+ /* istanbul ignore file */
13
+ ${schemaValidationCode}
14
+
15
+ module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
16
+ `
17
+
18
+ const file = path.join(__dirname, '..', 'lib', 'configValidator.js')
19
+ fs.writeFileSync(file, moduleCode)
20
+ console.log(`Saved ${file} file successfully`)
21
+ }
13
22
  })
14
23
 
15
24
  const defaultInitOptions = {
16
25
  connectionTimeout: 0, // 0 sec
17
- keepAliveTimeout: 5000, // 5 sec
26
+ keepAliveTimeout: 72000, // 72 seconds
27
+ forceCloseConnections: false, // keep-alive connections
18
28
  maxRequestsPerSocket: 0, // no limit
19
29
  requestTimeout: 0, // no limit
20
30
  bodyLimit: 1024 * 1024, // 1 MiB
@@ -28,27 +38,17 @@ const defaultInitOptions = {
28
38
  pluginTimeout: 10000,
29
39
  requestIdHeader: 'request-id',
30
40
  requestIdLogLabel: 'reqId',
31
- http2SessionTimeout: 5000
41
+ http2SessionTimeout: 72000, // 72 seconds
42
+ exposeHeadRoutes: true
32
43
  }
33
44
 
34
- function customRule0 (schemaParamValue, validatedParamValue, validationSchemaObject, currentDataPath, validatedParamObject, validatedParam) {
35
- validatedParamObject[validatedParam] = schemaParamValue
36
- return true
37
- }
38
-
39
- // We add a keyword that allow us to set default values
40
- ajv.addKeyword('setDefaultValue', {
41
- modifying: true,
42
- validate: customRule0,
43
- errors: false
44
- })
45
-
46
45
  const schema = {
47
46
  type: 'object',
48
47
  additionalProperties: false,
49
48
  properties: {
50
49
  connectionTimeout: { type: 'integer', default: defaultInitOptions.connectionTimeout },
51
50
  keepAliveTimeout: { type: 'integer', default: defaultInitOptions.keepAliveTimeout },
51
+ forceCloseConnections: { type: 'boolean', default: defaultInitOptions.forceCloseConnections },
52
52
  maxRequestsPerSocket: { type: 'integer', default: defaultInitOptions.maxRequestsPerSocket, nullable: true },
53
53
  requestTimeout: { type: 'integer', default: defaultInitOptions.requestTimeout },
54
54
  bodyLimit: { type: 'integer', default: defaultInitOptions.bodyLimit },
@@ -86,6 +86,7 @@ const schema = {
86
86
  requestIdHeader: { type: 'string', default: defaultInitOptions.requestIdHeader },
87
87
  requestIdLogLabel: { type: 'string', default: defaultInitOptions.requestIdLogLabel },
88
88
  http2SessionTimeout: { type: 'integer', default: defaultInitOptions.http2SessionTimeout },
89
+ exposeHeadRoutes: { type: 'boolean', default: defaultInitOptions.exposeHeadRoutes },
89
90
  // deprecated style of passing the versioning constraint
90
91
  versioning: {
91
92
  type: 'object',
@@ -113,18 +114,31 @@ const schema = {
113
114
  }
114
115
  }
115
116
 
116
- const validate = ajv.compile(schema)
117
-
118
- const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
119
- /* istanbul ignore file */
120
- // constant needed for customRule0 to work
121
- const self = {}
122
-
123
- ${pack(ajv, validate)}
124
-
125
- ${customRule0.toString()}
126
-
127
- module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
128
- `
117
+ const compiler = factory({}, {
118
+ customOptions: {
119
+ code: {
120
+ source: true,
121
+ lines: true,
122
+ optimize: 3
123
+ },
124
+ removeAdditional: true,
125
+ useDefaults: true,
126
+ coerceTypes: true,
127
+ keywords: [
128
+ {
129
+ keyword: 'setDefaultValue',
130
+ $data: true,
131
+ // error: false,
132
+ modifying: true,
133
+ valid: true,
134
+ code (keywordCxt) {
135
+ const { gen, it, schemaValue } = keywordCxt
136
+ const logicCode = gen.assign(_`${it.parentData}[${it.parentDataProperty}]`, schemaValue)
137
+ return logicCode
138
+ }
139
+ }
140
+ ]
141
+ }
142
+ })
129
143
 
130
- fs.writeFileSync(path.join(__dirname, '..', 'lib', 'configValidator.js'), moduleCode)
144
+ compiler({ schema })
@@ -59,7 +59,7 @@ section.
59
59
  - [`fastify-http-proxy`](https://github.com/fastify/fastify-http-proxy) Proxy
60
60
  your HTTP requests to another server, with hooks.
61
61
  - [`fastify-jwt`](https://github.com/fastify/fastify-jwt) JWT utils for Fastify,
62
- internally uses [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
62
+ internally uses [fast-jwt](https://github.com/nearform/fast-jwt).
63
63
  - [`fastify-leveldb`](https://github.com/fastify/fastify-leveldb) Plugin to
64
64
  share a common LevelDB connection across Fastify.
65
65
  - [`fastify-mongodb`](https://github.com/fastify/fastify-mongodb) Fastify
@@ -130,6 +130,7 @@ section.
130
130
  - [`@immobiliarelabs/fastify-metrics`](https://github.com/immobiliare/fastify-metrics)
131
131
  Minimalistic and opinionated plugin that collects usage/process metrics and
132
132
  dispatches to [statsd](https://github.com/statsd/statsd).
133
+ - [`@immobiliarelabs/fastify-sentry`](https://github.com/immobiliare/fastify-sentry) Sentry errors handler that just works! Install, add your DSN and you're good to go!
133
134
  - [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit)
134
135
  A plugin to close the server gracefully
135
136
  - [`@mgcrea/fastify-request-logger`](https://github.com/mgcrea/fastify-request-logger)
@@ -117,7 +117,7 @@ an `id` ), and then pass it to our validation library, anything passed through
117
117
  via `__proto__` would sneak in undetected.
118
118
 
119
119
  ### Oh joi!
120
- <a id="pp-oh-joi">
120
+ <a id="pp-oh-joi"></a>
121
121
 
122
122
  The first question is, of course, why does the validation module **joi** ignore
123
123
  the prototype and let potentially harmful data through? We asked ourselves the
@@ -383,9 +383,9 @@ Because this work is important, I decided to try and make it not just
383
383
  financially sustainable but to grow and expand it. There is so much to improve.
384
384
  This is exactly what motivates me to implement the new [commercial licensing
385
385
  plan](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-licensing-a-preview-f982662ee898)
386
- coming in March. You can ready more about it
386
+ coming in March. You can read more about it
387
387
  [here](https://web.archive.org/web/20190201220503/https://hueniverse.com/on-hapi-licensing-a-preview-f982662ee898).
388
388
 
389
389
  Of all the time consuming things, security is at the very top. I hope this story
390
- successful conveyed not just the technical details, but also the human drama and
390
+ successfully conveyed not just the technical details, but also the human drama and
391
391
  what it takes to keep the web secure.
@@ -0,0 +1,12 @@
1
+ # V4 Migration Guide
2
+
3
+ This guide is intended to help with migration from Fastify v3 to v4.
4
+
5
+ Before migrating to v4, please ensure that you have fixed all deprecation warningx from v3.
6
+ All v3 deprecations have been removed and they will no longer work after upgrading.
7
+
8
+ ## Breaking Changes
9
+
10
+ ### Deprecation of `app.use()`
11
+
12
+ Starting this version of Fastify, we have deprecated the use of `app.use()`. We have decided not to support the use of middlewares. Both [`middie`](https://github.com/fastify/middie) and [`fastify-express`](https://github.com/fastify/fastify-express) will still be there and maintained. Use Fastify's [hooks](./Hooks.md) instead.
@@ -2,7 +2,10 @@
2
2
 
3
3
  ## `Content-Type` Parser
4
4
  Natively, Fastify only supports `'application/json'` and `'text/plain'` content
5
- types. The default charset is `utf-8`. If you need to support different content
5
+ types. If the content type is not one of these, a `FST_ERR_CTP_INVALID_MEDIA_TYPE`
6
+ error will be thrown.
7
+
8
+ The default charset is `utf-8`. If you need to support different content
6
9
  types, you can use the `addContentTypeParser` API. *The default JSON and/or
7
10
  plain text parser can be changed or removed.*
8
11
 
@@ -18,6 +21,9 @@ available only in that scope and its children.
18
21
  Fastify automatically adds the parsed request payload to the [Fastify
19
22
  request](./Request.md) object which you can access with `request.body`.
20
23
 
24
+ Note that for `GET` and `HEAD` requests the payload is never parsed. For `OPTIONS` and `DELETE` requests the payload is only parsed if
25
+ the content type is given in the content-type header. If it is not given, the [catch-all](#catch-all) parser is not executed as with `POST`, `PUT` and `PATCH`, but the payload is simply not parsed.
26
+
21
27
  ### Usage
22
28
  ```js
23
29
  fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {
@@ -87,6 +93,7 @@ if (!fastify.hasContentTypeParser('application/jsoff')){
87
93
  }
88
94
  ```
89
95
 
96
+ =======
90
97
  #### removeContentTypeParser
91
98
 
92
99
  With `removeContentTypeParser` a single or an array of content types can be
@@ -56,9 +56,19 @@ From the [Hooks documentation](./Hooks.md#manage-errors-from-a-hook):
56
56
  > `done()` and Fastify will automatically close the request and send the
57
57
  > appropriate error code to the user.
58
58
 
59
- If you have defined a custom error handler for using `setErrorHandler` the error
60
- will be routed there. otherwise, it will be routed to Fastify’s generic error
61
- handler.
59
+ When a custom error handler has been defined through
60
+ [`setErrorHandler`](./Server.md#seterrorhandler), the custom error handler will
61
+ receive the error passed to the `done()` callback (or through other supported
62
+ automatic error handling mechanisms). If `setErrorHandler` has been used
63
+ multiple times to define multiple handlers, the error will be routed to the most
64
+ precedent handler defined within the error [encapsulation context](./Encapsulation.md).
65
+ Error handlers are fully encapsulated, so a `setErrorHandler` call within a
66
+ plugin will limit the error handler to that plugin's context.
67
+
68
+ The root error handler is Fastify's generic error handler. This error handler
69
+ will use the headers and status code in the `Error` object, if they exist. The
70
+ headers and status code will not be automatically set if a custom error handler
71
+ is provided.
62
72
 
63
73
  Some things to consider in your custom error handler:
64
74
 
@@ -70,13 +80,12 @@ Some things to consider in your custom error handler:
70
80
  headers (no serialization)
71
81
 
72
82
  - You can throw a new error in your custom error handler
73
- - errors (new error or the received error parameter re-thrown) - will trigger
74
- the `onError` lifecycle hook and send the error to the user
83
+ - errors (new error or the received error parameter re-thrown) - will call the parent `errorHandler`.
84
+ - `onError` hook will be triggered once only for the first error being thrown.
75
85
  - an error will not be triggered twice from a lifecycle hook - Fastify
76
86
  internally monitors the error invocation to avoid infinite loops for errors
77
87
  thrown in the reply phases of the lifecycle. (those after the route handler)
78
88
 
79
-
80
89
  ### Fastify Error Codes
81
90
  <a id="fastify-error-codes"></a>
82
91
 
@@ -85,6 +94,12 @@ Some things to consider in your custom error handler:
85
94
 
86
95
  The router received an invalid url.
87
96
 
97
+ <a name="FST_ERR_DUPLICATED_ROUTE"></a>
98
+ #### FST_ERR_DUPLICATED_ROUTE
99
+
100
+ The HTTP method already has a registered controller for that URL
101
+
102
+ <a name="FST_ERR_CTP_ALREADY_PRESENT"></a>
88
103
  #### FST_ERR_CTP_ALREADY_PRESENT
89
104
  <a id="FST_ERR_CTP_ALREADY_PRESENT"></a>
90
105
 
@@ -199,3 +214,33 @@ You cannot use `send` inside the `onError` hook.
199
214
  <a id="FST_ERR_SEND_UNDEFINED_ERR"></a>
200
215
 
201
216
  Undefined error has occurred.
217
+
218
+ <a name="FST_ERR_PLUGIN_NOT_VALID"></a>
219
+ #### FST_ERR_PLUGIN_NOT_VALID
220
+
221
+ Plugin must be a function or a promise.
222
+
223
+ <a name="FST_ERR_PLUGIN_TIMEOUT"></a>
224
+ #### FST_ERR_PLUGIN_TIMEOUT
225
+
226
+ Plugin did not start in time. Default timeout (in millis): `10000`
227
+
228
+ <a name="FST_ERR_HOOK_TIMEOUT"></a>
229
+ #### FST_ERR_HOOK_TIMEOUT
230
+
231
+ A callback for a hook timed out
232
+
233
+ <a name="FST_ERR_ROOT_PLG_BOOTED"></a>
234
+ #### FST_ERR_ROOT_PLG_BOOTED
235
+
236
+ Root plugin has already booted (mapped directly from `avvio`)
237
+
238
+ <a name="FST_ERR_PARENT_PLUGIN_BOOTED"></a>
239
+ #### FST_ERR_PARENT_PLUGIN_BOOTED
240
+
241
+ Impossible to load plugin because the parent (mapped directly from `avvio`)
242
+
243
+ <a name="FST_ERR_PLUGIN_CALLBACK_NOT_FN"></a>
244
+ #### FST_ERR_PLUGIN_CALLBACK_NOT_FN
245
+
246
+ Callback for a hook is not a function (mapped directly from `avvio`)
@@ -65,7 +65,7 @@ fastify.addHook('onRequest', async (request, reply) => {
65
65
  ```
66
66
 
67
67
  **Notice:** in the [onRequest](#onrequest) hook, `request.body` will always be
68
- `null`, because the body parsing happens before the
68
+ `undefined`, because the body parsing happens before the
69
69
  [preValidation](#prevalidation) hook.
70
70
 
71
71
  ### preParsing
@@ -95,7 +95,7 @@ fastify.addHook('preParsing', async (request, reply, payload) => {
95
95
  ```
96
96
 
97
97
  **Notice:** in the [preParsing](#preparsing) hook, `request.body` will always be
98
- `null`, because the body parsing happens before the
98
+ `undefined`, because the body parsing happens before the
99
99
  [preValidation](#prevalidation) hook.
100
100
 
101
101
  **Notice:** you should also add a `receivedEncodedLength` property to the
@@ -103,10 +103,6 @@ returned stream. This property is used to correctly match the request payload
103
103
  with the `Content-Length` header value. Ideally, this property should be updated
104
104
  on each received chunk.
105
105
 
106
- **Notice**: The old syntaxes `function(request, reply, done)` and `async
107
- function(request, reply)` for the parser are still supported but they are
108
- deprecated.
109
-
110
106
  ### preValidation
111
107
 
112
108
  If you are using the `preValidation` hook, you can change the payload before it
@@ -322,7 +318,7 @@ fastify.addHook('onRequest', (request, reply, done) => {
322
318
  fastify.addHook('preHandler', async (request, reply) => {
323
319
  await something()
324
320
  reply.send({ hello: 'world' })
325
- return reply // optional in this case, but it is a good practice
321
+ return reply // mandatory, so the request is not executed further
326
322
  })
327
323
  ```
328
324
 
@@ -419,6 +415,7 @@ fastify.addHook('onClose', async (instance) => {
419
415
  Triggered when a new route is registered. Listeners are passed a `routeOptions`
420
416
  object as the sole parameter. The interface is synchronous, and, as such, the
421
417
  listeners are not passed a callback. This hook is encapsulated.
418
+
422
419
  ```js
423
420
  fastify.addHook('onRoute', (routeOptions) => {
424
421
  //Some code
@@ -48,6 +48,7 @@ A "month" is defined as 30 consecutive days.
48
48
  | 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 |
49
49
  | 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 |
50
50
  | 3.0.0 | 2020-07-07 | TBD | 10, 12, 14, 16 |
51
+ | 4.0.0 | TBD | TBD | 14, 16 |
51
52
 
52
53
  ### CI tested operating systems
53
54
  <a id="supported-os"></a>
@@ -60,10 +61,10 @@ YAML workflow labels below:
60
61
 
61
62
  | OS | YAML Workflow Label | Package Manager | Node.js |
62
63
  |---------|------------------------|---------------------------|--------------|
63
- | Linux | `ubuntu-latest` | npm | 10,12,14,16 |
64
- | Linux | `ubuntu-18.04` | yarn,pnpm | 10,12 |
65
- | Windows | `windows-latest` | npm | 10,12,14,16 |
66
- | MacOS | `macos-latest` | npm | 10,12,14,16 |
64
+ | Linux | `ubuntu-latest` | npm | 14,16 |
65
+ | Linux | `ubuntu-18.04` | yarn,pnpm | 14,16 |
66
+ | Windows | `windows-latest` | npm | 14,16 |
67
+ | MacOS | `macos-latest` | npm | 14,16 |
67
68
 
68
69
  Using [yarn](https://yarnpkg.com/) might require passing the `--ignore-engines`
69
70
  flag.
@@ -59,12 +59,10 @@ object that exposes the following functions and properties:
59
59
  buffer, JSON, stream, or an Error object.
60
60
  - `.sent` - A boolean value that you can use if you need to know if `send` has
61
61
  already been called.
62
+ - `.hijack()` - interrupt the normal request lifecycle.
62
63
  - `.raw` - The
63
64
  [`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse)
64
65
  from Node core.
65
- - `.res` *(deprecated, use `.raw` instead)* - The
66
- [`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse)
67
- from Node core.
68
66
  - `.log` - The logger instance of the incoming request.
69
67
  - `.request` - The incoming request.
70
68
  - `.context` - Access the [Request's context](./Request.md) property.
@@ -125,6 +123,8 @@ fastify.get('/', async function (req, rep) {
125
123
  Sets a response header. If the value is omitted or undefined, it is coerced to
126
124
  `''`.
127
125
 
126
+ > Note: the header's value must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid characters will result in a 500 `TypeError` response.
127
+
128
128
  For more information, see
129
129
  [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_response_setheader_name_value).
130
130
 
@@ -205,6 +205,8 @@ Returns a boolean indicating if the specified header has been set.
205
205
  Redirects a request to the specified URL, the status code is optional, default
206
206
  to `302` (if status code is not already set by calling `code`).
207
207
 
208
+ > Note: the input URL must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will result in a 500 `TypeError` response.
209
+
208
210
  Example (no `reply.code()` call) sets status code to `302` and redirects to
209
211
  `/home`
210
212
  ```js
@@ -315,39 +317,38 @@ Another example of the misuse of `Reply.raw` is explained in
315
317
 
316
318
  As the name suggests, `.sent` is a property to indicate if a response has been
317
319
  sent via `reply.send()`.
320
+ It will also be `true` in case `reply.hijack()` was used.
318
321
 
319
322
  In case a route handler is defined as an async function or it returns a promise,
320
- it is possible to set `reply.sent = true` to indicate that the automatic
323
+ it is possible to call `reply.hijack()` to indicate that the automatic
321
324
  invocation of `reply.send()` once the handler promise resolve should be skipped.
322
- By setting `reply.sent = true`, an application claims full responsibility for
325
+ By calling `reply.hijack()`, an application claims full responsibility for
323
326
  the low-level request and response. Moreover, hooks will not be invoked.
324
327
 
325
- As an example:
328
+ *Modifying the `.sent` property directly is deprecated. Please use the aformentioned
329
+ `.hijack()` method to achieve the same effect.*
330
+
331
+ <a name="hijack"></a>
332
+ ### .hijack()
333
+ Sometimes you might need to halt the execution of the normal request lifecycle and
334
+ handle sending the response manually.
335
+
336
+ To achieve this, Fastify provides the `reply.hijack()` method that can be called
337
+ during the request lifecycle (At any point before `reply.send()` is called), and
338
+ allows you to prevent Fastify from sending the response, and from running the
339
+ remaining hooks (and user handler if the reply was hijacked before).
326
340
 
327
341
  ```js
328
342
  app.get('/', (req, reply) => {
329
- reply.sent = true
343
+ reply.hijack()
330
344
  reply.raw.end('hello world')
331
345
 
332
346
  return Promise.resolve('this will be skipped')
333
347
  })
334
348
  ```
335
349
 
336
- If the handler rejects, the error will be logged.
337
-
338
- ### .hijack()
339
- <a id="hijack"></a>
340
-
341
- Sometimes you might need to halt the execution of the normal request lifecycle
342
- and handle sending the response manually.
343
-
344
- To achieve this, Fastify provides the `reply.hijack()` method that can be called
345
- during the request lifecycle (At any point before `reply.send()` is called), and
346
- allows you to prevent Fastify from sending the response, and from running the
347
- remaining hooks (and user handler if the reply was hijacked before).
348
-
349
- NB (*): If `reply.raw` is used to send a response back to the user, `onResponse`
350
- hooks will still be executed
350
+ If `reply.raw` is used to send a response back to the user, the `onResponse`
351
+ hooks will still be executed.
351
352
 
352
353
  ### .send(data)
353
354
  <a id="send"></a>
@@ -12,10 +12,8 @@ Request is a core Fastify object containing the following fields:
12
12
  - `params` - the params matching the URL
13
13
  - [`headers`](#headers) - the headers getter and setter
14
14
  - `raw` - the incoming HTTP request from Node core
15
- - `req` *(deprecated, use `.raw` instead)* - the incoming HTTP request from Node
16
- core
17
15
  - `server` - The Fastify server instance, scoped to the current [encapsulation
18
- context](./Encapsulation.md)
16
+ >>>>>>> main:docs/Reference/Request.md
19
17
  - `id` - the request ID
20
18
  - `log` - the logger instance of the incoming request
21
19
  - `ip` - the IP address of the incoming request
@@ -32,7 +32,7 @@ fastify.route(options)
32
32
  ### Routes options
33
33
  <a id="options"></a>
34
34
 
35
- * `method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`,
35
+ *`method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`,
36
36
  `'POST'`, `'PUT'` and `'OPTIONS'`. It could also be an array of methods.
37
37
  * `url`: the path of the URL to match this route (alias: `path`).
38
38
  * `schema`: an object containing the schemas for the request and response. They
@@ -54,6 +54,7 @@ fastify.route(options)
54
54
  option, make sure to define it before the `GET` route.
55
55
  * `attachValidation`: attach `validationError` to request, if there is a schema
56
56
  validation error, instead of sending the error to the error handler.
57
+ The default [error format](https://ajv.js.org/api.html#error-objects) is the Ajv one.
57
58
  * `onRequest(request, reply, done)`: a [function](./Hooks.md#onrequest) as soon
58
59
  that a request is received, it could also be an array of functions.
59
60
  * `preParsing(request, reply, done)`: a [function](./Hooks.md#preparsing) called
@@ -280,11 +281,14 @@ As you can see, we are not calling `reply.send` to send back the data to the
280
281
  user. You just need to return the body and you are done!
281
282
 
282
283
  If you need it you can also send back the data to the user with `reply.send`.
284
+ In this case do not forget to `return reply` or `await reply` in your `async`
285
+ handler or you will introduce a race condition in certain situations.
286
+
283
287
  ```js
284
288
  fastify.get('/', options, async function (request, reply) {
285
289
  var data = await getData()
286
290
  var processed = await processData(data)
287
- reply.send(processed)
291
+ return reply.send(processed)
288
292
  })
289
293
  ```
290
294
 
@@ -316,24 +320,27 @@ fastify.get('/', options, async function (request, reply) {
316
320
  first one that happens takes precedence, the second value will be discarded,
317
321
  and a *warn* log will also be emitted because you tried to send a response
318
322
  twice.
323
+ * Calling `reply.send()` outside of the promise is possible, but requires
324
+ special attention. For more details read
325
+ [promise-resolution](#promise-resolution).
319
326
  * You cannot return `undefined`. For more details read
320
327
  [promise-resolution](#promise-resolution).
321
328
 
322
329
  ### Promise resolution
323
330
  <a id="promise-resolution"></a>
324
331
 
325
- If your handler is an `async` function or returns a promise, you should be aware
326
- of a special behavior that is necessary to support the callback and promise
327
- control-flow. If the handler's promise is resolved with `undefined`, it will be
328
- ignored causing the request to hang and an *error* log to be emitted.
332
+ If your handler is an `async` function or returns a promise, you should be aware of
333
+ a special behaviour which is necessary to support the callback and promise
334
+ control-flow. When the handler's promise is resolved, the reply will be
335
+ automatically sent with its value unless you explicitly await or return `reply`
336
+ in your handler.
329
337
 
330
- 1. If you want to use `async/await` or promises but return a value with
331
- `reply.send`:
332
- - **Do not** `return` any value.
338
+ 1. If you want to use `async/await` or promises but respond a value with `reply.send`:
339
+ - **Do** `return reply` / `await reply`.
333
340
  - **Do not** forget to call `reply.send`.
334
341
  2. If you want to use `async/await` or promises:
335
342
  - **Do not** use `reply.send`.
336
- - **Do not** return `undefined`.
343
+ - **Do** return the value that you want to send.
337
344
 
338
345
  In this way, we can support both `callback-style` and `async-await`, with the
339
346
  minimum trade-off. In spite of so much freedom we highly recommend to go with