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/.taprc CHANGED
@@ -4,3 +4,6 @@ flow: false
4
4
  check-coverage: true
5
5
  coverage: true
6
6
  node-arg: --allow-natives-syntax
7
+
8
+ files:
9
+ - 'test/**/*.test.js'
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>
@@ -10,7 +9,6 @@
10
9
  [![Package Manager CI](https://github.com/fastify/fastify/workflows/package-manager-ci/badge.svg)](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
11
10
  [![Web SIte](https://github.com/fastify/fastify/workflows/website/badge.svg)](https://github.com/fastify/fastify/actions/workflows/website.yml)
12
11
  [![Known Vulnerabilities](https://snyk.io/test/github/fastify/fastify/badge.svg)](https://snyk.io/test/github/fastify/fastify)
13
- [![Coverage Status](https://coveralls.io/repos/github/fastify/fastify/badge.svg?branch=main)](https://coveralls.io/github/fastify/fastify?branch=main)
14
12
  [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
15
13
 
16
14
  </div>
@@ -45,6 +43,8 @@ How can you efficiently handle the resources of your server, knowing that you ar
45
43
 
46
44
  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
45
 
46
+ 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.
47
+
48
48
  ### Quick start
49
49
 
50
50
  Create a folder and make it your current working directory:
@@ -88,11 +88,11 @@ If installing in an existing project, then Fastify can be installed into the pro
88
88
 
89
89
  Install with npm:
90
90
  ```sh
91
- npm i fastify --save
91
+ npm i fastify@next --save
92
92
  ```
93
93
  Install with yarn:
94
94
  ```sh
95
- yarn add fastify
95
+ yarn add fastify@next
96
96
  ```
97
97
 
98
98
  ### Example
@@ -116,7 +116,7 @@ fastify.get('/', (request, reply) => {
116
116
  })
117
117
 
118
118
  // Run the server!
119
- fastify.listen(3000, (err, address) => {
119
+ fastify.listen({ port: 3000 }, (err, address) => {
120
120
  if (err) throw err
121
121
  // Server is now listening on ${address}
122
122
  })
@@ -140,7 +140,7 @@ fastify.get('/', async (request, reply) => {
140
140
  return { hello: 'world' }
141
141
  })
142
142
 
143
- fastify.listen(3000, (err, address) => {
143
+ fastify.listen({ port: 3000 }, (err, address) => {
144
144
  if (err) throw err
145
145
  // Server is now listening on ${address}
146
146
  })
@@ -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,29 @@
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
18
27
  forceCloseConnections: false, // keep-alive connections
19
28
  maxRequestsPerSocket: 0, // no limit
20
29
  requestTimeout: 0, // no limit
@@ -29,21 +38,10 @@ const defaultInitOptions = {
29
38
  pluginTimeout: 10000,
30
39
  requestIdHeader: 'request-id',
31
40
  requestIdLogLabel: 'reqId',
32
- http2SessionTimeout: 5000
41
+ http2SessionTimeout: 72000, // 72 seconds
42
+ exposeHeadRoutes: true
33
43
  }
34
44
 
35
- function customRule0 (schemaParamValue, validatedParamValue, validationSchemaObject, currentDataPath, validatedParamObject, validatedParam) {
36
- validatedParamObject[validatedParam] = schemaParamValue
37
- return true
38
- }
39
-
40
- // We add a keyword that allow us to set default values
41
- ajv.addKeyword('setDefaultValue', {
42
- modifying: true,
43
- validate: customRule0,
44
- errors: false
45
- })
46
-
47
45
  const schema = {
48
46
  type: 'object',
49
47
  additionalProperties: false,
@@ -88,6 +86,7 @@ const schema = {
88
86
  requestIdHeader: { type: 'string', default: defaultInitOptions.requestIdHeader },
89
87
  requestIdLogLabel: { type: 'string', default: defaultInitOptions.requestIdLogLabel },
90
88
  http2SessionTimeout: { type: 'integer', default: defaultInitOptions.http2SessionTimeout },
89
+ exposeHeadRoutes: { type: 'boolean', default: defaultInitOptions.exposeHeadRoutes },
91
90
  // deprecated style of passing the versioning constraint
92
91
  versioning: {
93
92
  type: 'object',
@@ -115,18 +114,31 @@ const schema = {
115
114
  }
116
115
  }
117
116
 
118
- const validate = ajv.compile(schema)
119
-
120
- const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
121
- /* istanbul ignore file */
122
- // constant needed for customRule0 to work
123
- const self = {}
124
-
125
- ${pack(ajv, validate)}
126
-
127
- ${customRule0.toString()}
128
-
129
- module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
130
- `
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
+ })
131
143
 
132
- fs.writeFileSync(path.join(__dirname, '..', 'lib', 'configValidator.js'), moduleCode)
144
+ compiler({ schema })
@@ -0,0 +1,320 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ ## Database
4
+
5
+ Fastify's ecosystem provides a handful of
6
+ plugins for connecting to various database engines.
7
+ This guide covers engines that have Fastify
8
+ plugins maintained within the Fastify organization.
9
+
10
+ > If a plugin for your database of choice does not exist
11
+ > you can still use the database as Fastify is database agnostic.
12
+ > By following the examples of the database plugins listed in this guide,
13
+ > a plugin can be written for the missing database engine.
14
+
15
+ > If you would like to write your own Fastify plugin
16
+ > please take a look at the [plugins guide](./Plugins-Guide.md)
17
+
18
+ ### [MySQL](https://github.com/fastify/fastify-mysql)
19
+
20
+ Install the plugin by running `npm i fastify-mysql --save`.
21
+
22
+ *Usage:*
23
+
24
+ ```javascript
25
+ const fastify = require('fastify')()
26
+
27
+ fastify.register(require('fastify-mysql'), {
28
+ connectionString: 'mysql://root@localhost/mysql'
29
+ })
30
+
31
+ fastify.get('/user/:id', function(req, reply) {
32
+ fastify.mysql.query(
33
+ 'SELECT id, username, hash, salt FROM users WHERE id=?', [req.params.id],
34
+ function onResult (err, result) {
35
+ reply.send(err || result)
36
+ }
37
+ )
38
+ })
39
+
40
+ fastify.listen(3000, err => {
41
+ if (err) throw err
42
+ console.log(`server listening on ${fastify.server.address().port}`)
43
+ })
44
+ ```
45
+
46
+ ### [Postgres](https://github.com/fastify/fastify-postgres)
47
+ Install the plugin by running `npm i pg fastify-postgres --save`.
48
+
49
+ *Example*:
50
+
51
+ ```javascript
52
+ const fastify = require('fastify')()
53
+
54
+ fastify.register(require('fastify-postgres'), {
55
+ connectionString: 'postgres://postgres@localhost/postgres'
56
+ })
57
+
58
+ fastify.get('/user/:id', function (req, reply) {
59
+ fastify.pg.query(
60
+ 'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id],
61
+ function onResult (err, result) {
62
+ reply.send(err || result)
63
+ }
64
+ )
65
+ })
66
+
67
+ fastify.listen(3000, err => {
68
+ if (err) throw err
69
+ console.log(`server listening on ${fastify.server.address().port}`)
70
+ })
71
+ ```
72
+
73
+ ### [Redis](https://github.com/fastify/fastify-redis)
74
+ Install the plugin by running `npm i fastify-redis --save`
75
+
76
+ *Usage:*
77
+
78
+ ```javascript
79
+ 'use strict'
80
+
81
+ const fastify = require('fastify')()
82
+
83
+ fastify.register(require('fastify-redis'), { host: '127.0.0.1' })
84
+ // or
85
+ fastify.register(require('fastify-redis'), { url: 'redis://127.0.0.1', /* other redis options */ })
86
+
87
+ fastify.get('/foo', function (req, reply) {
88
+ const { redis } = fastify
89
+ redis.get(req.query.key, (err, val) => {
90
+ reply.send(err || val)
91
+ })
92
+ })
93
+
94
+ fastify.post('/foo', function (req, reply) {
95
+ const { redis } = fastify
96
+ redis.set(req.body.key, req.body.value, (err) => {
97
+ reply.send(err || { status: 'ok' })
98
+ })
99
+ })
100
+
101
+ fastify.listen(3000, err => {
102
+ if (err) throw err
103
+ console.log(`server listening on ${fastify.server.address().port}`)
104
+ })
105
+ ```
106
+
107
+ By default `fastify-redis` doesn't close
108
+ the client connection when Fastify server shuts down.
109
+ To opt-in to this behavior, register the client like so:
110
+
111
+ ```javascript
112
+ fastify.register(require('fastify-redis'), {
113
+ client: redis,
114
+ closeClient: true
115
+ })
116
+ ```
117
+
118
+ ### [Mongo](https://github.com/fastify/fastify-mongodb)
119
+ Install the plugin by running `npm i fastify-mongodb --save`
120
+
121
+ *Usage:*
122
+ ```javascript
123
+ const fastify = require('fastify')()
124
+
125
+ fastify.register(require('fastify-mongodb'), {
126
+ // force to close the mongodb connection when app stopped
127
+ // the default value is false
128
+ forceClose: true,
129
+
130
+ url: 'mongodb://mongo/mydb'
131
+ })
132
+
133
+ fastify.get('/user/:id', function (req, reply) {
134
+ // Or this.mongo.client.db('mydb').collection('users')
135
+ const users = this.mongo.db.collection('users')
136
+
137
+ // if the id is an ObjectId format, you need to create a new ObjectId
138
+ const id = this.mongo.ObjectId(req.params.id)
139
+ users.findOne({ id }, (err, user) => {
140
+ if (err) {
141
+ reply.send(err)
142
+ return
143
+ }
144
+ reply.send(user)
145
+ })
146
+ })
147
+
148
+ fastify.listen(3000, err => {
149
+ if (err) throw err
150
+ })
151
+ ```
152
+
153
+ ### [LevelDB](https://github.com/fastify/fastify-leveldb)
154
+ Install the plugin by running `https://github.com/fastify/fastify-leveldb`
155
+
156
+ *Usage:*
157
+ ```javascript
158
+ const fastify = require('fastify')()
159
+
160
+ fastify.register(
161
+ require('fastify-leveldb'),
162
+ { name: 'db' }
163
+ )
164
+
165
+ fastify.get('/foo', async function (req, reply) {
166
+ const val = await this.level.db.get(req.query.key)
167
+ return val
168
+ })
169
+
170
+ fastify.post('/foo', async function (req, reply) {
171
+ await this.level.db.put(req.body.key, req.body.value)
172
+ return { status: 'ok' }
173
+ })
174
+
175
+ fastify.listen(3000, err => {
176
+ if (err) throw err
177
+ console.log(`server listening on ${fastify.server.address().port}`)
178
+ })
179
+ ```
180
+
181
+ ### Writing plugin for a database library
182
+ We could write a plugin for a database
183
+ library too (e.g. Knex, Prisma, or TypeORM).
184
+ We will use [Knex](https://knexjs.org/) in our example.
185
+
186
+ ```javascript
187
+ 'use strict'
188
+
189
+ const fp = require('fastify-plugin')
190
+ const knex = require('knex')
191
+
192
+ function knexPlugin(fastify, options, done) {
193
+ if(!fastify.knex) {
194
+ const knex = knex(options)
195
+ fastify.decorate('knex', knex)
196
+
197
+ fastify.addHook('onClose', (fastify, done) => {
198
+ if (fastify.knex === knex) {
199
+ fastify.knex.destroy(done)
200
+ }
201
+ })
202
+ }
203
+
204
+ done()
205
+ }
206
+
207
+ export default fp(plugin, { name: 'fastify-knex-example' })
208
+ ```
209
+
210
+ ### Writing a plugin for a database engine
211
+
212
+ In this example, we will create a basic Fastify MySQL plugin from scratch (it is
213
+ a stripped-down example, please use the official plugin in production).
214
+
215
+ ```javascript
216
+ const fp = require('fp')
217
+ const mysql = require('mysql2/promise')
218
+
219
+ function fastifyMysql(fastify, options, done) {
220
+ const connection = mysql.createConnection(options)
221
+
222
+ if (!fastify.mysql) {
223
+ fastify.decorate('mysql', connection)
224
+ }
225
+
226
+ fastify.addHook('onClose', (fastify, done) => connection.end().then(done).catch(done))
227
+
228
+ done()
229
+ }
230
+
231
+ export default fp(fastifyMysql, { name: 'fastify-mysql-example' })
232
+ ```
233
+
234
+ ### Migrations
235
+
236
+ Database schema migrations are an integral part of database management and
237
+ development. Migrations provide a repeatable and testable way to modify a
238
+ database's schema and to prevent data loss.
239
+
240
+ As stated at the beginning of the guide, Fastify is database agnostic and any
241
+ NodeJS database migration tool can be used with it. We will give an example of
242
+ using [Postgrator](https://www.npmjs.com/package/postgrator) which has support
243
+ for Postgres, MySQL and SQL Server. For MongoDB migrations, please check
244
+ [migrate-mongo](https://www.npmjs.com/package/migrate-mongo).
245
+
246
+ #### [Postgrator](https://www.npmjs.com/package/postgrator)
247
+
248
+ Postgrator is NodeJS SQL migration tool that uses a directory of SQL scripts to
249
+ alter the database schema. Each file an migrations folder need to follow the
250
+ pattern: ` [version].[action].[optional-description].sql`.
251
+
252
+ **version:** must be an incrementing number (e.g. `001` or a timestamp).
253
+
254
+ **action:** should be `do` or `undo`. `do` implements the version, `undo`
255
+ reverts it. Think about it like `up` and `down` in other migration tools.
256
+
257
+ **optional-description** describes which changes migration makes. Although
258
+ optional, it should be used for all migrations as it makes it easier for
259
+ everyone to know which changes are made in a migration.
260
+
261
+ In our example we are going to have a single migration that creates a `users`
262
+ table and we are going to use `Postgrator` to run the migration.
263
+
264
+ > Run `npm install pg postgrator` to install dependencies needed for the
265
+ > example.
266
+
267
+ ```sql
268
+ // 001.do.create-users-table.sql
269
+ CREATE TABLE IF NOT EXISTS users (
270
+ id SERIAL PRIMARY KEY NOT NULL,
271
+ created_at DATE NOT NULL DEFAULT CURRENT_DATE,
272
+ firstName TEXT NOT NULL,
273
+ lastName TEXT NOT NULL
274
+ );
275
+ ```
276
+ ```javascript
277
+ const pg = require('pg')
278
+ const Postgrator = require('postgrator')
279
+ const path = require('path')
280
+
281
+ async function migrate() {
282
+ const client = new pg.Client({
283
+ host: 'localhost',
284
+ port: 5432,
285
+ database: 'example',
286
+ user: 'example',
287
+ password: 'example',
288
+ });
289
+
290
+ try {
291
+ const postgrator = new Postgrator({
292
+ migrationPattern: path.join(__dirname, '/migrations/*'),
293
+ driver: 'pg',
294
+ database: 'example',
295
+ schemaTable: 'migrations',
296
+ currentSchema: 'public', // Postgres and MS SQL Server only
297
+ execQuery: (query) => client.query(query),
298
+ });
299
+
300
+ const result = await postgrator.migrate()
301
+
302
+ if (result.length === 0) {
303
+ console.log(
304
+ 'No migrations run for schema "public". Already at the latest one.'
305
+ )
306
+ }
307
+
308
+ console.log('Migration done.')
309
+
310
+ process.exitCode = 0
311
+ } catch(err) {
312
+ console.error(error)
313
+ process.exitCode = 1
314
+ }
315
+
316
+ await client.end()
317
+ }
318
+
319
+ migrate()
320
+ ```
@@ -8,6 +8,9 @@ section.
8
8
 
9
9
  #### [Core](#core)
10
10
 
11
+ - [`aws-lambda-fastify`](https://github.com/fastify/aws-lambda-fastify) allows you to
12
+ easily build serverless web applications/services and RESTful APIs using Fastify
13
+ on top of AWS Lambda and Amazon API Gateway.
11
14
  - [`fastify-accepts`](https://github.com/fastify/fastify-accepts) to have
12
15
  [accepts](https://www.npmjs.com/package/accepts) in your request object.
13
16
  - [`fastify-accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer)
@@ -295,6 +298,8 @@ section.
295
298
  An error handling plugin for Fastify that uses enhanced HTTP errors.
296
299
  - [`fastify-https-redirect`](https://github.com/tomsvogel/fastify-https-redirect)
297
300
  Fastify plugin for auto-redirect from HTTP to HTTPS.
301
+ - [`fatify-impressions`](https://github.com/manju4ever/fastify-impressions) Fastify
302
+ plugin to track impressions of all the routes.
298
303
  - [`fastify-influxdb`](https://github.com/alex-ppg/fastify-influxdb) Fastify
299
304
  InfluxDB plugin connecting to an InfluxDB instance via the Influx default
300
305
  package.
@@ -334,6 +339,8 @@ section.
334
339
  - [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose)
335
340
  Fastify Mongoose plugin that connects to a MongoDB via the Mongoose plugin
336
341
  with support for Models.
342
+ - [`fastify-mqtt`](https://github.com/love-lena/fastify-mqtt) Plugin to share
343
+ [mqtt](https://www.npmjs.com/package/mqtt) client across Fastify.
337
344
  - [`fastify-msgpack`](https://github.com/kenriortega/fastify-msgpack) Fastify
338
345
  and MessagePack, together at last. Uses @msgpack/msgpack by default.
339
346
  - [`fastify-multer`](https://github.com/fox1t/fastify-multer) Multer is a plugin
@@ -484,6 +491,8 @@ section.
484
491
  waterline. Decorates Fastify with waterline models.
485
492
  - [`fastify-webpack-hmr`](https://github.com/lependu/fastify-webpack-hmr)
486
493
  Webpack hot module reloading plugin for Fastify.
494
+ - [`fastify-webpack-hot`](https://github.com/gajus/fastify-webpack-hot)
495
+ Webpack Hot Module Replacement for Fastify.
487
496
  - [`fastify-ws`](https://github.com/gj/fastify-ws) WebSocket integration for
488
497
  Fastify — with support for WebSocket lifecycle hooks instead of a single
489
498
  handler function. Built upon [ws](https://github.com/websockets/ws) and
@@ -45,7 +45,7 @@ fastify.get('/', function (request, reply) {
45
45
  })
46
46
 
47
47
  // Run the server!
48
- fastify.listen(3000, function (err, address) {
48
+ fastify.listen({ port: 3000 }, function (err, address) {
49
49
  if (err) {
50
50
  fastify.log.error(err)
51
51
  process.exit(1)
@@ -76,7 +76,7 @@ fastify.get('/', async (request, reply) => {
76
76
 
77
77
  const start = async () => {
78
78
  try {
79
- await fastify.listen(3000)
79
+ await fastify.listen({ port: 3000 })
80
80
  } catch (err) {
81
81
  fastify.log.error(err)
82
82
  process.exit(1)
@@ -102,7 +102,7 @@ above, and more!
102
102
  > `0.0.0.0` like so:
103
103
  >
104
104
  > ```js
105
- > fastify.listen(3000, '0.0.0.0', function (err, address) {
105
+ > fastify.listen({ port: 3000, host: '0.0.0.0' }, function (err, address) {
106
106
  > if (err) {
107
107
  > fastify.log.error(err)
108
108
  > process.exit(1)
@@ -139,7 +139,7 @@ const fastify = Fastify({
139
139
 
140
140
  fastify.register(firstRoute)
141
141
 
142
- fastify.listen(3000, function (err, address) {
142
+ fastify.listen({ port: 3000 }, function (err, address) {
143
143
  if (err) {
144
144
  fastify.log.error(err)
145
145
  process.exit(1)
@@ -156,7 +156,7 @@ const fastify = require('fastify')({
156
156
 
157
157
  fastify.register(require('./our-first-route'))
158
158
 
159
- fastify.listen(3000, function (err, address) {
159
+ fastify.listen({ port: 3000 }, function (err, address) {
160
160
  if (err) {
161
161
  fastify.log.error(err)
162
162
  process.exit(1)
@@ -214,7 +214,7 @@ const fastify = Fastify({
214
214
  fastify.register(dbConnector)
215
215
  fastify.register(firstRoute)
216
216
 
217
- fastify.listen(3000, function (err, address) {
217
+ fastify.listen({ port: 3000 }, function (err, address) {
218
218
  if (err) {
219
219
  fastify.log.error(err)
220
220
  process.exit(1)
@@ -232,7 +232,7 @@ const fastify = require('fastify')({
232
232
  fastify.register(require('./our-db-connector'))
233
233
  fastify.register(require('./our-first-route'))
234
234
 
235
- fastify.listen(3000, function (err, address) {
235
+ fastify.listen({ port: 3000 }, function (err, address) {
236
236
  if (err) {
237
237
  fastify.log.error(err)
238
238
  process.exit(1)
@@ -401,7 +401,7 @@ const fastify = Fastify()
401
401
 
402
402
  ///...
403
403
 
404
- fastify.listen(3000, (err, address) => {
404
+ fastify.listen({ port: 3000 }, (err, address) => {
405
405
  if (err) {
406
406
  fastify.log.error(err)
407
407
  process.exit(1)
@@ -52,7 +52,7 @@ function init() {
52
52
 
53
53
  if (require.main === module) {
54
54
  // called directly i.e. "node app"
55
- init().listen(3000, (err) => {
55
+ init().listen({ port: 3000 }, (err) => {
56
56
  if (err) console.error(err);
57
57
  console.log('server listening on 3000');
58
58
  });
@@ -277,11 +277,11 @@ async function start() {
277
277
  const port = process.env.PORT || 3000
278
278
 
279
279
  // You must listen on all IPV4 addresses in Cloud Run
280
- const address = IS_GOOGLE_CLOUD_RUN ? "0.0.0.0" : undefined
280
+ const host = IS_GOOGLE_CLOUD_RUN ? "0.0.0.0" : undefined
281
281
 
282
282
  try {
283
283
  const server = build()
284
- const address = await server.listen(port, address)
284
+ const address = await server.listen({ port, host })
285
285
  console.log(`Listening on ${address}`)
286
286
  } catch (err) {
287
287
  console.error(err)
@@ -47,7 +47,7 @@ const server = require('./app')({
47
47
  }
48
48
  })
49
49
 
50
- server.listen(3000, (err, address) => {
50
+ server.listen({ port: 3000 }, (err, address) => {
51
51
  if (err) {
52
52
  server.log.error(err)
53
53
  process.exit(1)
@@ -255,7 +255,7 @@ tap.test('GET `/` route', t => {
255
255
 
256
256
  t.teardown(() => fastify.close())
257
257
 
258
- fastify.listen(0, (err) => {
258
+ fastify.listen({ port: 0 }, (err) => {
259
259
  t.error(err)
260
260
 
261
261
  request({
@@ -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.