fastify 3.4.1 → 3.7.0
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/docs/ContentTypeParser.md +3 -0
- package/docs/Decorators.md +2 -0
- package/docs/Ecosystem.md +2 -1
- package/docs/Lifecycle.md +2 -2
- package/docs/Logging.md +1 -1
- package/docs/Reply.md +18 -0
- package/docs/Request.md +5 -1
- package/docs/Routes.md +2 -2
- package/docs/Server.md +55 -4
- package/docs/TypeScript.md +2 -1
- package/docs/Validation-and-Serialization.md +11 -5
- package/examples/simple.mjs +27 -0
- package/fastify.js +55 -7
- package/lib/contentTypeParser.js +4 -0
- package/lib/context.js +1 -16
- package/lib/errors.js +10 -2
- package/lib/fourOhFour.js +4 -3
- package/lib/logger.js +1 -1
- package/lib/pluginUtils.js +15 -0
- package/lib/reply.js +3 -3
- package/lib/request.js +26 -1
- package/lib/route.js +7 -3
- package/lib/symbols.js +2 -1
- package/lib/validation.js +1 -0
- package/lib/warnings.js +3 -0
- package/lib/wrapThenable.js +2 -2
- package/package.json +5 -5
- package/test/custom-parser.test.js +30 -0
- package/test/emit-warning.test.js +31 -0
- package/test/esm/index.test.js +15 -2
- package/test/esm/named-exports.mjs +13 -0
- package/test/fastify-instance.test.js +33 -1
- package/test/http2/secure.test.js +11 -0
- package/test/https/https.test.js +26 -0
- package/test/internals/request.test.js +8 -5
- package/test/internals/version.test.js +43 -0
- package/test/listen.test.js +16 -0
- package/test/logger.test.js +1 -1
- package/test/plugin.test.js +108 -0
- package/test/request-error.test.js +81 -0
- package/test/route.test.js +27 -0
- package/test/trust-proxy.test.js +42 -5
- package/test/types/decorate-request-reply.test-d.ts +18 -0
- package/test/types/instance.test-d.ts +27 -9
- package/test/types/logger.test-d.ts +63 -1
- package/test/types/register.test-d.ts +16 -0
- package/test/types/request.test-d.ts +1 -1
- package/test/types/schema.test-d.ts +5 -0
- package/test/validation-error-handling.test.js +66 -0
- package/types/instance.d.ts +7 -13
- package/types/logger.d.ts +90 -10
- package/types/register.d.ts +1 -0
- package/types/request.d.ts +20 -11
- package/types/schema.d.ts +2 -2
|
@@ -126,3 +126,84 @@ test('default clientError handler ignores ECONNRESET', t => {
|
|
|
126
126
|
client.write('\r\n\r\n')
|
|
127
127
|
})
|
|
128
128
|
})
|
|
129
|
+
|
|
130
|
+
test('error handler binding', t => {
|
|
131
|
+
t.plan(5)
|
|
132
|
+
|
|
133
|
+
const fastify = Fastify()
|
|
134
|
+
|
|
135
|
+
fastify.setErrorHandler(function (err, request, reply) {
|
|
136
|
+
t.strictEqual(this, fastify)
|
|
137
|
+
reply
|
|
138
|
+
.code(err.statusCode)
|
|
139
|
+
.type('application/json; charset=utf-8')
|
|
140
|
+
.send(err)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
fastify.post('/', function (req, reply) {
|
|
144
|
+
reply.send({ hello: 'world' })
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
fastify.inject({
|
|
148
|
+
method: 'POST',
|
|
149
|
+
url: '/',
|
|
150
|
+
simulate: {
|
|
151
|
+
error: true
|
|
152
|
+
},
|
|
153
|
+
body: {
|
|
154
|
+
text: '12345678901234567890123456789012345678901234567890'
|
|
155
|
+
}
|
|
156
|
+
}, (err, res) => {
|
|
157
|
+
t.error(err)
|
|
158
|
+
t.strictEqual(res.statusCode, 400)
|
|
159
|
+
t.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8')
|
|
160
|
+
t.deepEqual(JSON.parse(res.payload), {
|
|
161
|
+
error: 'Bad Request',
|
|
162
|
+
message: 'Simulated',
|
|
163
|
+
statusCode: 400
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
test('encapsulated error handler binding', t => {
|
|
169
|
+
t.plan(7)
|
|
170
|
+
|
|
171
|
+
const fastify = Fastify()
|
|
172
|
+
|
|
173
|
+
fastify.register(function (app, opts, next) {
|
|
174
|
+
app.decorate('hello', 'world')
|
|
175
|
+
t.strictEqual(app.hello, 'world')
|
|
176
|
+
app.post('/', function (req, reply) {
|
|
177
|
+
reply.send({ hello: 'world' })
|
|
178
|
+
})
|
|
179
|
+
app.setErrorHandler(function (err, request, reply) {
|
|
180
|
+
t.strictEqual(this.hello, 'world')
|
|
181
|
+
reply
|
|
182
|
+
.code(err.statusCode)
|
|
183
|
+
.type('application/json; charset=utf-8')
|
|
184
|
+
.send(err)
|
|
185
|
+
})
|
|
186
|
+
next()
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
fastify.inject({
|
|
190
|
+
method: 'POST',
|
|
191
|
+
url: '/',
|
|
192
|
+
simulate: {
|
|
193
|
+
error: true
|
|
194
|
+
},
|
|
195
|
+
body: {
|
|
196
|
+
text: '12345678901234567890123456789012345678901234567890'
|
|
197
|
+
}
|
|
198
|
+
}, (err, res) => {
|
|
199
|
+
t.error(err)
|
|
200
|
+
t.strictEqual(res.statusCode, 400)
|
|
201
|
+
t.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8')
|
|
202
|
+
t.deepEqual(res.json(), {
|
|
203
|
+
error: 'Bad Request',
|
|
204
|
+
message: 'Simulated',
|
|
205
|
+
statusCode: 400
|
|
206
|
+
})
|
|
207
|
+
t.strictEqual(fastify.hello, undefined)
|
|
208
|
+
})
|
|
209
|
+
})
|
package/test/route.test.js
CHANGED
|
@@ -190,6 +190,33 @@ test('invalid schema - route', t => {
|
|
|
190
190
|
})
|
|
191
191
|
})
|
|
192
192
|
|
|
193
|
+
test('same route definition object on multiple prefixes', async t => {
|
|
194
|
+
t.plan(2)
|
|
195
|
+
|
|
196
|
+
const routeObject = {
|
|
197
|
+
handler: () => {},
|
|
198
|
+
method: 'GET',
|
|
199
|
+
url: '/simple'
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const fastify = Fastify()
|
|
203
|
+
|
|
204
|
+
fastify.register(async function (f) {
|
|
205
|
+
f.addHook('onRoute', (routeOptions) => {
|
|
206
|
+
t.is(routeOptions.url, '/v1/simple')
|
|
207
|
+
})
|
|
208
|
+
f.route(routeObject)
|
|
209
|
+
}, { prefix: '/v1' })
|
|
210
|
+
fastify.register(async function (f) {
|
|
211
|
+
f.addHook('onRoute', (routeOptions) => {
|
|
212
|
+
t.is(routeOptions.url, '/v2/simple')
|
|
213
|
+
})
|
|
214
|
+
f.route(routeObject)
|
|
215
|
+
}, { prefix: '/v2' })
|
|
216
|
+
|
|
217
|
+
await fastify.ready()
|
|
218
|
+
})
|
|
219
|
+
|
|
193
220
|
test('path can be specified in place of uri', t => {
|
|
194
221
|
t.plan(3)
|
|
195
222
|
const fastify = Fastify()
|
package/test/trust-proxy.test.js
CHANGED
|
@@ -5,13 +5,17 @@ const test = t.test
|
|
|
5
5
|
const sget = require('simple-get').concat
|
|
6
6
|
const fastify = require('..')
|
|
7
7
|
|
|
8
|
-
const sgetForwardedRequest = (app, forHeader, path) => {
|
|
8
|
+
const sgetForwardedRequest = (app, forHeader, path, protoHeader) => {
|
|
9
|
+
const headers = {
|
|
10
|
+
'X-Forwarded-For': forHeader,
|
|
11
|
+
'X-Forwarded-Host': 'example.com'
|
|
12
|
+
}
|
|
13
|
+
if (protoHeader) {
|
|
14
|
+
headers['X-Forwarded-Proto'] = protoHeader
|
|
15
|
+
}
|
|
9
16
|
sget({
|
|
10
17
|
method: 'GET',
|
|
11
|
-
headers:
|
|
12
|
-
'X-Forwarded-For': forHeader,
|
|
13
|
-
'X-Forwarded-Host': 'example.com'
|
|
14
|
-
},
|
|
18
|
+
headers: headers,
|
|
15
19
|
url: 'http://localhost:' + app.server.address().port + path
|
|
16
20
|
}, () => {})
|
|
17
21
|
}
|
|
@@ -28,6 +32,10 @@ const testRequestValues = (t, req, options) => {
|
|
|
28
32
|
if (options.ips) {
|
|
29
33
|
t.deepEqual(req.ips, options.ips, 'gets ips from x-forwarded-for')
|
|
30
34
|
}
|
|
35
|
+
if (options.protocol) {
|
|
36
|
+
t.ok(req.protocol, 'protocol is defined')
|
|
37
|
+
t.equal(req.protocol, options.protocol, 'gets protocol from x-forwarded-proto')
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
test('trust proxy, not add properties to node req', (t) => {
|
|
@@ -131,3 +139,32 @@ test('trust proxy IP addresses', (t) => {
|
|
|
131
139
|
sgetForwardedRequest(app, '3.3.3.3, 2.2.2.2, 1.1.1.1', '/trustproxyipaddrs')
|
|
132
140
|
})
|
|
133
141
|
})
|
|
142
|
+
|
|
143
|
+
test('trust proxy protocol', (t) => {
|
|
144
|
+
t.plan(13)
|
|
145
|
+
const app = fastify({
|
|
146
|
+
trustProxy: true
|
|
147
|
+
})
|
|
148
|
+
app.get('/trustproxyprotocol', function (req, reply) {
|
|
149
|
+
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem' })
|
|
150
|
+
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
151
|
+
})
|
|
152
|
+
app.get('/trustproxynoprotocol', function (req, reply) {
|
|
153
|
+
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http' })
|
|
154
|
+
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
155
|
+
})
|
|
156
|
+
app.get('/trustproxyprotocols', function (req, reply) {
|
|
157
|
+
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor' })
|
|
158
|
+
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
t.tearDown(app.close.bind(app))
|
|
162
|
+
|
|
163
|
+
app.listen(0, (err) => {
|
|
164
|
+
app.server.unref()
|
|
165
|
+
t.error(err)
|
|
166
|
+
sgetForwardedRequest(app, '1.1.1.1', '/trustproxyprotocol', 'lorem')
|
|
167
|
+
sgetForwardedRequest(app, '1.1.1.1', '/trustproxynoprotocol')
|
|
168
|
+
sgetForwardedRequest(app, '1.1.1.1', '/trustproxyprotocols', 'ipsum, dolor')
|
|
169
|
+
})
|
|
170
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import fastify from '../../fastify'
|
|
2
|
+
import { expectType } from 'tsd'
|
|
3
|
+
|
|
4
|
+
type TestType = void
|
|
5
|
+
|
|
6
|
+
declare module '../../fastify' {
|
|
7
|
+
interface FastifyRequest {
|
|
8
|
+
testProp: TestType;
|
|
9
|
+
}
|
|
10
|
+
interface FastifyReply {
|
|
11
|
+
testProp: TestType;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fastify().get('/', (req, res) => {
|
|
16
|
+
expectType<TestType>(req.testProp)
|
|
17
|
+
expectType<TestType>(res.testProp)
|
|
18
|
+
})
|
|
@@ -16,16 +16,17 @@ expectAssignable<FastifyInstance>(server.addSchema({
|
|
|
16
16
|
expectType<Record<string, unknown>>(server.getSchemas())
|
|
17
17
|
expectType<unknown>(server.getSchema('SchemaId'))
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
expectAssignable<FastifyInstance>(
|
|
20
|
+
server.setErrorHandler(function (error, request, reply) {
|
|
21
|
+
expectAssignable<FastifyInstance>(this)
|
|
22
|
+
})
|
|
23
|
+
)
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
expectType<FastifyError>(error)
|
|
28
|
-
})
|
|
25
|
+
expectAssignable<FastifyInstance>(
|
|
26
|
+
server.setErrorHandler<FastifyError>(function (error, request, reply) {
|
|
27
|
+
expectType<FastifyError>(error)
|
|
28
|
+
})
|
|
29
|
+
)
|
|
29
30
|
|
|
30
31
|
function fastifyErrorHandler (this: FastifyInstance, error: FastifyError) {}
|
|
31
32
|
server.setErrorHandler(fastifyErrorHandler)
|
|
@@ -51,6 +52,23 @@ expectError(server.setReplySerializer(serializerWithInvalidReturn))
|
|
|
51
52
|
function invalidSchemaErrorFormatter () {}
|
|
52
53
|
expectError(server.setSchemaErrorFormatter(invalidSchemaErrorFormatter))
|
|
53
54
|
|
|
55
|
+
// test listen method callback
|
|
56
|
+
expectAssignable<void>(server.listen(3000, '', 0, (err, address) => {}))
|
|
57
|
+
expectAssignable<void>(server.listen('3000', '', 0, (err, address) => {}))
|
|
58
|
+
expectAssignable<void>(server.listen(3000, '', (err, address) => {}))
|
|
59
|
+
expectAssignable<void>(server.listen('3000', '', (err, address) => {}))
|
|
60
|
+
expectAssignable<void>(server.listen(3000, (err, address) => {}))
|
|
61
|
+
expectAssignable<void>(server.listen('3000', (err, address) => {}))
|
|
62
|
+
|
|
63
|
+
// test listen method promise
|
|
64
|
+
expectAssignable<PromiseLike<string>>(server.listen(3000))
|
|
65
|
+
expectAssignable<PromiseLike<string>>(server.listen('3000'))
|
|
66
|
+
expectAssignable<PromiseLike<string>>(server.listen(3000, '', 0))
|
|
67
|
+
expectAssignable<PromiseLike<string>>(server.listen('3000', '', 0))
|
|
68
|
+
expectAssignable<PromiseLike<string>>(server.listen(3000, ''))
|
|
69
|
+
expectAssignable<PromiseLike<string>>(server.listen('3000', ''))
|
|
70
|
+
|
|
71
|
+
// test listen opts objects
|
|
54
72
|
expectAssignable<PromiseLike<string>>(server.listen({ port: 3000 }))
|
|
55
73
|
expectAssignable<PromiseLike<string>>(server.listen({ port: 3000, host: '0.0.0.0' }))
|
|
56
74
|
expectAssignable<PromiseLike<string>>(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 }))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expectType, expectError } from 'tsd'
|
|
2
|
-
import fastify, { FastifyLogFn, LogLevel, FastifyLoggerInstance } from '../../fastify'
|
|
2
|
+
import fastify, { FastifyLogFn, LogLevel, FastifyLoggerInstance, FastifyError } from '../../fastify'
|
|
3
3
|
import { Server, IncomingMessage, ServerResponse } from 'http'
|
|
4
4
|
import * as pino from 'pino'
|
|
5
5
|
|
|
@@ -85,3 +85,65 @@ const serverWithAutoInferredPino = fastify({
|
|
|
85
85
|
})
|
|
86
86
|
|
|
87
87
|
expectType<pino.Logger>(serverWithAutoInferredPino.log)
|
|
88
|
+
|
|
89
|
+
const serverAutoInferredPinoPrettyBooleanOption = fastify({
|
|
90
|
+
logger: {
|
|
91
|
+
prettyPrint: true
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
expectType<FastifyLoggerInstance>(serverAutoInferredPinoPrettyBooleanOption.log)
|
|
96
|
+
|
|
97
|
+
const serverAutoInferredPinoPrettyObjectOption = fastify({
|
|
98
|
+
logger: {
|
|
99
|
+
prettyPrint: {
|
|
100
|
+
translateTime: true,
|
|
101
|
+
levelFirst: false,
|
|
102
|
+
messageKey: 'msg',
|
|
103
|
+
timestampKey: 'time',
|
|
104
|
+
messageFormat: false,
|
|
105
|
+
colorize: true,
|
|
106
|
+
crlf: false,
|
|
107
|
+
errorLikeObjectKeys: ['err', 'error'],
|
|
108
|
+
errorProps: '',
|
|
109
|
+
search: 'foo == `bar`',
|
|
110
|
+
ignore: 'pid,hostname',
|
|
111
|
+
suppressFlushSyncWarning: true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
expectType<FastifyLoggerInstance>(serverAutoInferredPinoPrettyObjectOption.log)
|
|
117
|
+
|
|
118
|
+
const serverAutoInferredSerializerObjectOption = fastify({
|
|
119
|
+
logger: {
|
|
120
|
+
serializers: {
|
|
121
|
+
req (IncomingMessage) {
|
|
122
|
+
return {
|
|
123
|
+
method: 'method',
|
|
124
|
+
url: 'url',
|
|
125
|
+
version: 'version',
|
|
126
|
+
hostname: 'hostname',
|
|
127
|
+
remoteAddress: 'remoteAddress',
|
|
128
|
+
remotePort: 80,
|
|
129
|
+
other: ''
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
res (ServerResponse) {
|
|
133
|
+
return {
|
|
134
|
+
statusCode: 'statusCode'
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
err (FastifyError) {
|
|
138
|
+
return {
|
|
139
|
+
other: '',
|
|
140
|
+
type: 'type',
|
|
141
|
+
message: 'msg',
|
|
142
|
+
stack: 'stack'
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
expectType<FastifyLoggerInstance>(serverAutoInferredSerializerObjectOption.log)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expectAssignable, expectError } from 'tsd'
|
|
2
|
+
import fastify, { FastifyInstance, FastifyPluginAsync } from '../../fastify'
|
|
3
|
+
|
|
4
|
+
const testPluginOptsAsync: FastifyPluginAsync = async function (_instance, _opts) { }
|
|
5
|
+
|
|
6
|
+
// Type validation
|
|
7
|
+
expectError(fastify().register(testPluginOptsAsync, { prefix: 1 }))
|
|
8
|
+
expectError(fastify().register(testPluginOptsAsync, { logLevel: () => ({}) }))
|
|
9
|
+
expectError(fastify().register(testPluginOptsAsync, { logSerializers: () => ({}) }))
|
|
10
|
+
expectError(fastify().register({}))
|
|
11
|
+
|
|
12
|
+
expectAssignable<FastifyInstance>(
|
|
13
|
+
fastify().register(
|
|
14
|
+
testPluginOptsAsync, { prefix: '/example', logLevel: 'info', logSerializers: { key: (value: any) => `${value}` } }
|
|
15
|
+
)
|
|
16
|
+
)
|
|
@@ -53,7 +53,7 @@ const getHandler: RouteHandler = function (request, _reply) {
|
|
|
53
53
|
expectType<RequestQuerystringDefault>(request.query)
|
|
54
54
|
expectType<any>(request.id)
|
|
55
55
|
expectType<FastifyLoggerInstance>(request.log)
|
|
56
|
-
expectType<RawRequestDefaultExpression['socket']>(request.
|
|
56
|
+
expectType<RawRequestDefaultExpression['socket']>(request.socket)
|
|
57
57
|
expectType<Error & { validation: any; validationContext: string } | undefined>(request.validationError)
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expectAssignable, expectError } from 'tsd'
|
|
2
2
|
import fastify, { FastifyInstance } from '../../fastify'
|
|
3
|
+
import Ajv = require('ajv')
|
|
3
4
|
|
|
4
5
|
const server = fastify()
|
|
5
6
|
|
|
@@ -31,6 +32,10 @@ expectAssignable<FastifyInstance>(server.get(
|
|
|
31
32
|
() => { }
|
|
32
33
|
))
|
|
33
34
|
|
|
35
|
+
expectAssignable<FastifyInstance>(server.setValidatorCompiler(({ schema }) => {
|
|
36
|
+
return new Ajv().compile(schema)
|
|
37
|
+
}))
|
|
38
|
+
|
|
34
39
|
expectError(server.get(
|
|
35
40
|
'/unknown-schema-prop',
|
|
36
41
|
{
|
|
@@ -97,6 +97,72 @@ test('should be able to use setErrorHandler specify custom validation error', t
|
|
|
97
97
|
})
|
|
98
98
|
})
|
|
99
99
|
|
|
100
|
+
test('error inside custom error handler should have validationContext', t => {
|
|
101
|
+
t.plan(1)
|
|
102
|
+
|
|
103
|
+
const fastify = Fastify()
|
|
104
|
+
|
|
105
|
+
fastify.post('/', {
|
|
106
|
+
schema,
|
|
107
|
+
validatorCompiler: ({ schema, method, url, httpPart }) => {
|
|
108
|
+
return function (data) {
|
|
109
|
+
return { error: new Error('this failed') }
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, function (req, reply) {
|
|
113
|
+
t.fail('should not be here')
|
|
114
|
+
reply.code(200).send(req.body.name)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
fastify.setErrorHandler(function (error, request, reply) {
|
|
118
|
+
t.strictEqual(error.validationContext, 'body')
|
|
119
|
+
reply.status(500).send(error)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
fastify.inject({
|
|
123
|
+
method: 'POST',
|
|
124
|
+
payload: {
|
|
125
|
+
name: 'michelangelo',
|
|
126
|
+
work: 'artist'
|
|
127
|
+
},
|
|
128
|
+
url: '/'
|
|
129
|
+
}, () => {})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('error inside custom error handler should have validationContext if specified by custom error handler', t => {
|
|
133
|
+
t.plan(1)
|
|
134
|
+
|
|
135
|
+
const fastify = Fastify()
|
|
136
|
+
|
|
137
|
+
fastify.post('/', {
|
|
138
|
+
schema,
|
|
139
|
+
validatorCompiler: ({ schema, method, url, httpPart }) => {
|
|
140
|
+
return function (data) {
|
|
141
|
+
const error = new Error('this failed')
|
|
142
|
+
error.validationContext = 'customContext'
|
|
143
|
+
return { error: error }
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}, function (req, reply) {
|
|
147
|
+
t.fail('should not be here')
|
|
148
|
+
reply.code(200).send(req.body.name)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
fastify.setErrorHandler(function (error, request, reply) {
|
|
152
|
+
t.strictEqual(error.validationContext, 'customContext')
|
|
153
|
+
reply.status(500).send(error)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
fastify.inject({
|
|
157
|
+
method: 'POST',
|
|
158
|
+
payload: {
|
|
159
|
+
name: 'michelangelo',
|
|
160
|
+
work: 'artist'
|
|
161
|
+
},
|
|
162
|
+
url: '/'
|
|
163
|
+
}, () => {})
|
|
164
|
+
})
|
|
165
|
+
|
|
100
166
|
test('should be able to attach validation to request', t => {
|
|
101
167
|
t.plan(3)
|
|
102
168
|
|
package/types/instance.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface FastifyInstance<
|
|
|
21
21
|
> {
|
|
22
22
|
server: RawServer;
|
|
23
23
|
prefix: string;
|
|
24
|
+
version: string | undefined;
|
|
24
25
|
log: Logger;
|
|
25
26
|
|
|
26
27
|
addSchema(schema: unknown): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
|
|
@@ -46,10 +47,10 @@ export interface FastifyInstance<
|
|
|
46
47
|
inject(opts: InjectOptions | string): Promise<LightMyRequestResponse>;
|
|
47
48
|
inject(): LightMyRequestChain;
|
|
48
49
|
|
|
49
|
-
listen(port: number, address: string, backlog: number, callback: (err: Error, address: string) => void): void;
|
|
50
|
-
listen(port: number, address: string, callback: (err: Error, address: string) => void): void;
|
|
51
|
-
listen(port: number, callback: (err: Error, address: string) => void): void;
|
|
52
|
-
listen(port: number, address?: string, backlog?: number): Promise<string>;
|
|
50
|
+
listen(port: number | string, address: string, backlog: number, callback: (err: Error, address: string) => void): void;
|
|
51
|
+
listen(port: number | string, address: string, callback: (err: Error, address: string) => void): void;
|
|
52
|
+
listen(port: number | string, callback: (err: Error, address: string) => void): void;
|
|
53
|
+
listen(port: number | string, address?: string, backlog?: number): Promise<string>;
|
|
53
54
|
listen(opts: { port: number; host?: string; backlog?: number }, callback: (err: Error, address: string) => void): void;
|
|
54
55
|
listen(opts: { port: number; host?: string; backlog?: number }): Promise<string>;
|
|
55
56
|
|
|
@@ -58,13 +59,6 @@ export interface FastifyInstance<
|
|
|
58
59
|
|
|
59
60
|
register: FastifyRegister<FastifyInstance<RawServer, RawRequest, RawReply, Logger> & PromiseLike<undefined>>;
|
|
60
61
|
|
|
61
|
-
/**
|
|
62
|
-
* This method will throw a `FST_ERR_MISSING_MIDDLEWARE` error unless support
|
|
63
|
-
* for Express-style middlewares is first enabled. Visit
|
|
64
|
-
* https://fastify.io/docs/latest/Middleware/ for more info.
|
|
65
|
-
*/
|
|
66
|
-
use(...args: unknown[]): unknown;
|
|
67
|
-
|
|
68
62
|
route<
|
|
69
63
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
|
70
64
|
ContextConfig = ContextConfigDefault
|
|
@@ -237,14 +231,14 @@ export interface FastifyInstance<
|
|
|
237
231
|
*/
|
|
238
232
|
setNotFoundHandler<RouteGeneric extends RouteGenericInterface = RouteGenericInterface>(
|
|
239
233
|
handler: (request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric>) => void
|
|
240
|
-
):
|
|
234
|
+
): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
|
|
241
235
|
|
|
242
236
|
/**
|
|
243
237
|
* Set a function that will be called whenever an error happens
|
|
244
238
|
*/
|
|
245
239
|
setErrorHandler<TError extends Error = FastifyError, RouteGeneric extends RouteGenericInterface = RouteGenericInterface>(
|
|
246
240
|
handler: (this: FastifyInstance<RawServer, RawRequest, RawReply, Logger>, error: TError, request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric>) => void
|
|
247
|
-
):
|
|
241
|
+
): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
|
|
248
242
|
|
|
249
243
|
/**
|
|
250
244
|
* Set the schema validator for all routes.
|
package/types/logger.d.ts
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Rationale for not directly importing types from @types/pino for use in fastify interfaces:
|
|
3
|
+
* - pino does not itself provide types so the types from @types must be used.
|
|
4
|
+
* - the types from @types are unofficial and the preference is to avoid using them or requiring them as a dependency of fastify.
|
|
5
|
+
* - the goal is to provide the minimum viable type definitions necessary to use fastify's official logger, pino.
|
|
6
|
+
* - the types provided should cover the basic use cases for the majority of fastify users while also being easy to maintain.
|
|
7
|
+
* - for advanced use cases needing the full set of types, users should be directed to manually install the unofficial types with
|
|
8
|
+
* `npm i -D @types/pino` and to supply their own logger instance as described at https://www.fastify.io/docs/latest/Logging/.
|
|
9
|
+
* - some fastify contributors have volunteered to maintain official types within pino (https://github.com/pinojs/pino/issues/910)
|
|
10
|
+
* in which case if the proposal is followed through with then in the future fastify will be able to directly import the full
|
|
11
|
+
* set of types rather than only duplicating and maintaining the subset chosen for providing a minimum viable logger api.
|
|
12
|
+
*
|
|
13
|
+
* Relevant discussions:
|
|
14
|
+
*
|
|
15
|
+
* https://github.com/fastify/fastify/pull/2550
|
|
16
|
+
* https://github.com/pinojs/pino/issues/910
|
|
17
|
+
* https://github.com/fastify/fastify/pull/1532
|
|
18
|
+
* https://github.com/fastify/fastify/issues/649
|
|
19
|
+
*/
|
|
20
|
+
|
|
1
21
|
import { FastifyError } from 'fastify-error'
|
|
2
22
|
import { RawServerBase, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression } from './utils'
|
|
3
23
|
import { FastifyRequest, RequestGenericInterface } from './request'
|
|
@@ -30,6 +50,63 @@ export interface FastifyLoggerInstance {
|
|
|
30
50
|
child(bindings: Bindings): FastifyLoggerInstance;
|
|
31
51
|
}
|
|
32
52
|
|
|
53
|
+
// This interface is accurate for pino 6.3 and was copied from the following permalink:
|
|
54
|
+
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/72c9bd83316bd31e93ab86d64ddf598d922f33cd/types/pino/index.d.ts#L514-L567
|
|
55
|
+
export interface PrettyOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Translate the epoch time value into a human readable date and time string.
|
|
58
|
+
* This flag also can set the format string to apply when translating the date to human readable format.
|
|
59
|
+
* The default format is yyyy-mm-dd HH:MM:ss.l o in UTC.
|
|
60
|
+
* For a list of available pattern letters see the {@link https://www.npmjs.com/package/dateformat|dateformat documentation}.
|
|
61
|
+
*/
|
|
62
|
+
translateTime?: boolean | string;
|
|
63
|
+
/**
|
|
64
|
+
* If set to true, it will print the name of the log level as the first field in the log line. Default: `false`.
|
|
65
|
+
*/
|
|
66
|
+
levelFirst?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The key in the JSON object to use as the highlighted message. Default: "msg".
|
|
69
|
+
*/
|
|
70
|
+
messageKey?: string;
|
|
71
|
+
/**
|
|
72
|
+
* The key in the JSON object to use for timestamp display. Default: "time".
|
|
73
|
+
*/
|
|
74
|
+
timestampKey?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Format output of message, e.g. {level} - {pid} will output message: INFO - 1123 Default: `false`.
|
|
77
|
+
*/
|
|
78
|
+
messageFormat?: false | string;
|
|
79
|
+
/**
|
|
80
|
+
* If set to true, will add color information to the formatted output message. Default: `false`.
|
|
81
|
+
*/
|
|
82
|
+
colorize?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Appends carriage return and line feed, instead of just a line feed, to the formatted log line.
|
|
85
|
+
*/
|
|
86
|
+
crlf?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Define the log keys that are associated with error like objects. Default: ["err", "error"]
|
|
89
|
+
*/
|
|
90
|
+
errorLikeObjectKeys?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* When formatting an error object, display this list of properties.
|
|
93
|
+
* The list should be a comma separated list of properties. Default: ''
|
|
94
|
+
*/
|
|
95
|
+
errorProps?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Specify a search pattern according to {@link http://jmespath.org|jmespath}
|
|
98
|
+
*/
|
|
99
|
+
search?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Ignore one or several keys. Example: "time,hostname"
|
|
102
|
+
*/
|
|
103
|
+
ignore?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Suppress warning on first synchronous flushing.
|
|
106
|
+
*/
|
|
107
|
+
suppressFlushSyncWarning?: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
33
110
|
/**
|
|
34
111
|
* Fastify Custom Logger options. To enable configuration of all Pino options,
|
|
35
112
|
* refer to this example:
|
|
@@ -41,24 +118,27 @@ export interface FastifyLoggerOptions<
|
|
|
41
118
|
RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>
|
|
42
119
|
> {
|
|
43
120
|
serializers?: {
|
|
44
|
-
req
|
|
45
|
-
method
|
|
46
|
-
url
|
|
47
|
-
version
|
|
48
|
-
hostname
|
|
49
|
-
remoteAddress
|
|
50
|
-
remotePort
|
|
121
|
+
req?: (req: RawRequest) => {
|
|
122
|
+
method?: string;
|
|
123
|
+
url?: string;
|
|
124
|
+
version?: string;
|
|
125
|
+
hostname?: string;
|
|
126
|
+
remoteAddress?: string;
|
|
127
|
+
remotePort?: number;
|
|
128
|
+
[key: string]: unknown;
|
|
51
129
|
};
|
|
52
|
-
err
|
|
130
|
+
err?: (err: FastifyError) => {
|
|
53
131
|
type: string;
|
|
54
132
|
message: string;
|
|
55
133
|
stack: string;
|
|
56
|
-
[key: string]:
|
|
134
|
+
[key: string]: unknown;
|
|
57
135
|
};
|
|
58
|
-
res
|
|
136
|
+
res?: (res: RawReply) => {
|
|
59
137
|
statusCode: string | number;
|
|
138
|
+
[key: string]: unknown;
|
|
60
139
|
};
|
|
61
140
|
};
|
|
62
141
|
level?: string;
|
|
63
142
|
genReqId?: <RequestGeneric extends RequestGenericInterface = RequestGenericInterface>(req: FastifyRequest<RequestGeneric, RawServer, RawRequest>) => string;
|
|
143
|
+
prettyPrint?: boolean | PrettyOptions;
|
|
64
144
|
}
|
package/types/register.d.ts
CHANGED
package/types/request.d.ts
CHANGED
|
@@ -22,20 +22,29 @@ export interface FastifyRequest<
|
|
|
22
22
|
params: RouteGeneric['Params'];
|
|
23
23
|
raw: RawRequest;
|
|
24
24
|
query: RouteGeneric['Querystring'];
|
|
25
|
-
headers: RawRequest['headers'] & RouteGeneric['Headers']; // this enables the developer to extend the existing http(s|2) headers list
|
|
26
25
|
log: FastifyLoggerInstance;
|
|
27
26
|
body: RouteGeneric['Body'];
|
|
28
|
-
|
|
29
|
-
ips?: string[];
|
|
30
|
-
hostname: string;
|
|
31
|
-
url: string;
|
|
32
|
-
method: string;
|
|
33
|
-
routerPath: string;
|
|
34
|
-
routerMethod: string;
|
|
35
|
-
is404: boolean;
|
|
27
|
+
|
|
36
28
|
/** in order for this to be used the user should ensure they have set the attachValidation option. */
|
|
37
29
|
validationError?: Error & { validation: any; validationContext: string };
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated Use `raw` property
|
|
33
|
+
*/
|
|
34
|
+
readonly req: RawRequest;
|
|
35
|
+
readonly headers: RawRequest['headers'] & RouteGeneric['Headers']; // this enables the developer to extend the existing http(s|2) headers list
|
|
36
|
+
readonly ip: string;
|
|
37
|
+
readonly ips?: string[];
|
|
38
|
+
readonly hostname: string;
|
|
39
|
+
readonly url: string;
|
|
40
|
+
readonly protocol: 'http' | 'https';
|
|
41
|
+
readonly method: string;
|
|
42
|
+
readonly routerPath: string;
|
|
43
|
+
readonly routerMethod: string;
|
|
44
|
+
readonly is404: boolean;
|
|
45
|
+
readonly socket: RawRequest['socket'];
|
|
46
|
+
|
|
47
|
+
// Prefer `socket` over deprecated `connection` property in node 13.0.0 or higher
|
|
48
|
+
// @deprecated
|
|
49
|
+
readonly connection: RawRequest['socket'];
|
|
41
50
|
}
|