fastify 3.27.3 → 4.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.taprc +3 -0
- package/README.md +7 -7
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +47 -35
- package/docs/Guides/Database.md +320 -0
- package/docs/Guides/Getting-Started.md +7 -7
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Serverless.md +3 -3
- package/docs/Guides/Testing.md +2 -2
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +4 -0
- package/docs/Reference/Decorators.md +2 -2
- package/docs/Reference/Encapsulation.md +2 -2
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/HTTP2.md +3 -3
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Plugins.md +3 -3
- package/docs/Reference/Reply.md +23 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +22 -15
- package/docs/Reference/Server.md +69 -119
- package/docs/Reference/TypeScript.md +20 -22
- package/docs/Reference/Validation-and-Serialization.md +30 -55
- package/docs/Type-Providers.md +257 -0
- package/examples/asyncawait.js +1 -1
- package/examples/benchmark/hooks-benchmark-async-await.js +1 -1
- package/examples/benchmark/hooks-benchmark.js +1 -1
- package/examples/benchmark/simple.js +1 -1
- package/examples/hooks.js +2 -2
- package/examples/http2.js +1 -1
- package/examples/https.js +1 -1
- package/examples/parser.js +1 -1
- package/examples/route-prefix.js +1 -1
- package/examples/shared-schema.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/examples/simple.js +1 -1
- package/examples/simple.mjs +1 -1
- package/examples/typescript-server.ts +1 -1
- package/examples/use-plugin.js +1 -1
- package/fastify.d.ts +34 -22
- package/fastify.js +40 -36
- package/lib/configValidator.js +902 -1023
- package/lib/contentTypeParser.js +6 -16
- package/lib/context.js +36 -10
- package/lib/decorate.js +3 -1
- package/lib/error-handler.js +158 -0
- package/lib/error-serializer.js +257 -0
- package/lib/errors.js +43 -9
- package/lib/fourOhFour.js +31 -20
- package/lib/handleRequest.js +10 -13
- package/lib/hooks.js +14 -9
- package/lib/pluginOverride.js +0 -3
- package/lib/pluginUtils.js +3 -2
- package/lib/reply.js +29 -158
- package/lib/request.js +13 -10
- package/lib/route.js +131 -138
- package/lib/schema-controller.js +2 -2
- package/lib/schemas.js +27 -1
- package/lib/server.js +241 -116
- package/lib/symbols.js +4 -3
- package/lib/validation.js +2 -1
- package/lib/warnings.js +4 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +37 -39
- package/test/404s.test.js +258 -125
- package/test/500s.test.js +3 -3
- package/test/als.test.js +1 -1
- package/test/async-await.test.js +20 -76
- package/test/bodyLimit.test.js +1 -1
- package/test/build-certificate.js +6 -7
- package/test/case-insensitive.test.js +4 -4
- package/test/close-pipelining.test.js +2 -2
- package/test/close.test.js +11 -11
- package/test/content-parser.test.js +32 -0
- package/test/context-config.test.js +52 -0
- package/test/custom-http-server.test.js +14 -7
- package/test/custom-parser-async.test.js +1 -66
- package/test/custom-parser.test.js +92 -159
- package/test/custom-querystring-parser.test.js +3 -3
- package/test/decorator.test.js +11 -13
- package/test/delete.test.js +6 -6
- package/test/encapsulated-error-handler.test.js +50 -0
- package/test/esm/index.test.js +0 -14
- package/test/fastify-instance.test.js +4 -4
- package/test/fluent-schema.test.js +4 -4
- package/test/genReqId.test.js +1 -1
- package/test/get.test.js +4 -4
- package/test/handler-context.test.js +2 -2
- package/test/head.test.js +1 -1
- package/test/helper.js +19 -4
- package/test/hooks-async.test.js +15 -48
- package/test/hooks.on-ready.test.js +10 -5
- package/test/hooks.test.js +78 -119
- package/test/http2/closing.test.js +10 -16
- package/test/http2/constraint.test.js +1 -1
- package/test/http2/head.test.js +1 -1
- package/test/http2/plain.test.js +1 -1
- package/test/http2/secure-with-fallback.test.js +1 -1
- package/test/http2/secure.test.js +1 -1
- package/test/http2/unknown-http-method.test.js +4 -10
- package/test/https/custom-https-server.test.js +12 -6
- package/test/https/https.test.js +1 -1
- package/test/input-validation.js +3 -3
- package/test/internals/handleRequest.test.js +6 -43
- package/test/internals/initialConfig.test.js +41 -12
- package/test/internals/logger.test.js +2 -2
- package/test/internals/reply.test.js +281 -40
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.deprecated.test.js +202 -0
- package/test/listen.test.js +118 -150
- package/test/logger.test.js +82 -42
- package/test/maxRequestsPerSocket.test.js +8 -6
- package/test/middleware.test.js +2 -25
- package/test/nullable-validation.test.js +53 -16
- package/test/output-validation.test.js +1 -1
- package/test/plugin.test.js +47 -21
- package/test/pretty-print.test.js +22 -10
- package/test/promises.test.js +1 -1
- package/test/proto-poisoning.test.js +6 -6
- package/test/register.test.js +3 -3
- package/test/reply-error.test.js +126 -15
- package/test/request-error.test.js +3 -6
- package/test/route-hooks.test.js +18 -18
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +206 -22
- package/test/router-options.test.js +2 -2
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +25 -20
- package/test/schema-serialization.test.js +9 -9
- package/test/schema-special-usage.test.js +5 -153
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +2 -2
- package/test/stream.test.js +82 -23
- package/test/throw.test.js +8 -5
- package/test/trust-proxy.test.js +6 -6
- package/test/type-provider.test.js +20 -0
- package/test/types/fastify.test-d.ts +10 -18
- package/test/types/import.js +2 -0
- package/test/types/import.ts +1 -0
- package/test/types/instance.test-d.ts +68 -17
- package/test/types/logger.test-d.ts +44 -15
- package/test/types/reply.test-d.ts +2 -1
- package/test/types/route.test-d.ts +8 -2
- package/test/types/schema.test-d.ts +2 -39
- package/test/types/type-provider.test-d.ts +417 -0
- package/test/url-rewriting.test.js +3 -3
- package/test/validation-error-handling.test.js +8 -8
- package/test/versioned-routes.test.js +30 -18
- package/test/wrapThenable.test.js +7 -6
- package/types/content-type-parser.d.ts +17 -8
- package/types/hooks.d.ts +102 -59
- package/types/instance.d.ts +244 -118
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/reply.d.ts +18 -12
- package/types/request.d.ts +10 -5
- package/types/route.d.ts +42 -31
- package/types/schema.d.ts +1 -1
- package/types/type-provider.d.ts +99 -0
- package/types/utils.d.ts +1 -1
- package/lib/schema-compilers.js +0 -12
- package/test/emit-warning.test.js +0 -166
package/.taprc
CHANGED
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
|
[](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
|
11
10
|
[](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
|
12
11
|
[](https://snyk.io/test/github/fastify/fastify)
|
|
13
|
-
[](https://coveralls.io/github/fastify/fastify?branch=main)
|
|
14
12
|
[](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
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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:
|
|
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:
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
|
|
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
|
+
```
|
|
@@ -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)
|
|
@@ -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
|
|
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,
|
|
284
|
+
const address = await server.listen({ port, host })
|
|
285
285
|
console.log(`Listening on ${address}`)
|
|
286
286
|
} catch (err) {
|
|
287
287
|
console.error(err)
|
package/docs/Guides/Testing.md
CHANGED
|
@@ -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.
|
|
@@ -21,6 +21,9 @@ available only in that scope and its children.
|
|
|
21
21
|
Fastify automatically adds the parsed request payload to the [Fastify
|
|
22
22
|
request](./Request.md) object which you can access with `request.body`.
|
|
23
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
|
+
|
|
24
27
|
### Usage
|
|
25
28
|
```js
|
|
26
29
|
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) {
|
|
@@ -90,6 +93,7 @@ if (!fastify.hasContentTypeParser('application/jsoff')){
|
|
|
90
93
|
}
|
|
91
94
|
```
|
|
92
95
|
|
|
96
|
+
=======
|
|
93
97
|
#### removeContentTypeParser
|
|
94
98
|
|
|
95
99
|
With `removeContentTypeParser` a single or an array of content types can be
|
|
@@ -265,7 +265,7 @@ server.decorateReply('view', function (template, args) {
|
|
|
265
265
|
// Another rendering engine
|
|
266
266
|
})
|
|
267
267
|
|
|
268
|
-
server.listen(3000)
|
|
268
|
+
server.listen({ port: 3000 })
|
|
269
269
|
```
|
|
270
270
|
|
|
271
271
|
|
|
@@ -291,7 +291,7 @@ server.register(async function (server, opts) {
|
|
|
291
291
|
})
|
|
292
292
|
}, { prefix: '/bar' })
|
|
293
293
|
|
|
294
|
-
server.listen(3000)
|
|
294
|
+
server.listen({ port: 3000 })
|
|
295
295
|
```
|
|
296
296
|
|
|
297
297
|
### Getters and Setters
|