fastify 3.27.2 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +47 -35
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +4 -0
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Reply.md +23 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +17 -10
- package/docs/Reference/Server.md +48 -63
- package/docs/Reference/TypeScript.md +11 -13
- package/docs/Reference/Validation-and-Serialization.md +28 -53
- package/docs/Type-Providers.md +257 -0
- package/examples/hooks.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/fastify.d.ts +34 -22
- package/fastify.js +37 -35
- 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 +28 -157
- 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 +219 -116
- package/lib/symbols.js +4 -3
- package/lib/validation.js +2 -1
- package/lib/warnings.js +2 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +31 -35
- package/test/404s.test.js +243 -110
- package/test/500s.test.js +2 -2
- package/test/async-await.test.js +13 -69
- 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 +0 -65
- package/test/custom-parser.test.js +54 -121
- package/test/decorator.test.js +1 -3
- package/test/delete.test.js +5 -5
- 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/get.test.js +3 -3
- package/test/helper.js +18 -3
- package/test/hooks-async.test.js +14 -47
- package/test/hooks.on-ready.test.js +9 -4
- package/test/hooks.test.js +58 -99
- package/test/http2/closing.test.js +5 -11
- package/test/http2/unknown-http-method.test.js +3 -9
- package/test/https/custom-https-server.test.js +12 -6
- package/test/input-validation.js +2 -2
- package/test/internals/handleRequest.test.js +3 -40
- package/test/internals/initialConfig.test.js +33 -12
- package/test/internals/reply.test.js +245 -3
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.test.js +84 -1
- package/test/logger.test.js +80 -40
- package/test/maxRequestsPerSocket.test.js +6 -4
- package/test/middleware.test.js +2 -25
- package/test/nullable-validation.test.js +51 -14
- package/test/plugin.test.js +31 -5
- package/test/pretty-print.test.js +22 -10
- package/test/reply-error.test.js +123 -12
- package/test/request-error.test.js +2 -5
- package/test/route-hooks.test.js +17 -17
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +204 -20
- package/test/router-options.test.js +1 -1
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +24 -19
- package/test/schema-serialization.test.js +9 -9
- package/test/schema-special-usage.test.js +14 -81
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +1 -1
- package/test/stream.test.js +23 -12
- package/test/throw.test.js +8 -5
- 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 +35 -14
- package/test/types/logger.test-d.ts +44 -15
- 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/validation-error-handling.test.js +8 -8
- package/test/versioned-routes.test.js +28 -16
- 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 +124 -104
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/reply.d.ts +16 -11
- 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/test/async-await.test.js
CHANGED
|
@@ -79,7 +79,7 @@ test('ignore the result of the promise if reply.send is called beforehand (undef
|
|
|
79
79
|
const payload = { hello: 'world' }
|
|
80
80
|
|
|
81
81
|
server.get('/', async function awaitMyFunc (req, reply) {
|
|
82
|
-
reply.send(payload)
|
|
82
|
+
await reply.send(payload)
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
t.teardown(server.close.bind(server))
|
|
@@ -104,7 +104,7 @@ test('ignore the result of the promise if reply.send is called beforehand (objec
|
|
|
104
104
|
const payload = { hello: 'world2' }
|
|
105
105
|
|
|
106
106
|
server.get('/', async function awaitMyFunc (req, reply) {
|
|
107
|
-
reply.send(payload)
|
|
107
|
+
await reply.send(payload)
|
|
108
108
|
return { hello: 'world' }
|
|
109
109
|
})
|
|
110
110
|
|
|
@@ -139,7 +139,7 @@ test('server logs an error if reply.send is called and a value is returned via a
|
|
|
139
139
|
})
|
|
140
140
|
|
|
141
141
|
fastify.get('/', async (req, reply) => {
|
|
142
|
-
reply.send({ hello: 'world' })
|
|
142
|
+
await reply.send({ hello: 'world' })
|
|
143
143
|
return { hello: 'world2' }
|
|
144
144
|
})
|
|
145
145
|
|
|
@@ -160,7 +160,7 @@ test('ignore the result of the promise if reply.send is called beforehand (undef
|
|
|
160
160
|
const payload = { hello: 'world' }
|
|
161
161
|
|
|
162
162
|
server.get('/', async function awaitMyFunc (req, reply) {
|
|
163
|
-
reply.send(payload)
|
|
163
|
+
await reply.send(payload)
|
|
164
164
|
})
|
|
165
165
|
|
|
166
166
|
t.teardown(server.close.bind(server))
|
|
@@ -185,7 +185,7 @@ test('ignore the result of the promise if reply.send is called beforehand (objec
|
|
|
185
185
|
const payload = { hello: 'world2' }
|
|
186
186
|
|
|
187
187
|
server.get('/', async function awaitMyFunc (req, reply) {
|
|
188
|
-
reply.send(payload)
|
|
188
|
+
await reply.send(payload)
|
|
189
189
|
return { hello: 'world' }
|
|
190
190
|
})
|
|
191
191
|
|
|
@@ -279,11 +279,13 @@ test('support reply decorators with await', t => {
|
|
|
279
279
|
setImmediate(() => {
|
|
280
280
|
this.send({ hello: 'world' })
|
|
281
281
|
})
|
|
282
|
+
|
|
283
|
+
return this
|
|
282
284
|
})
|
|
283
285
|
|
|
284
286
|
fastify.get('/', async (req, reply) => {
|
|
285
287
|
await sleep(1)
|
|
286
|
-
reply.wow()
|
|
288
|
+
await reply.wow()
|
|
287
289
|
})
|
|
288
290
|
|
|
289
291
|
fastify.inject({
|
|
@@ -296,24 +298,6 @@ test('support reply decorators with await', t => {
|
|
|
296
298
|
})
|
|
297
299
|
})
|
|
298
300
|
|
|
299
|
-
test('support 204', t => {
|
|
300
|
-
t.plan(2)
|
|
301
|
-
|
|
302
|
-
const fastify = Fastify()
|
|
303
|
-
|
|
304
|
-
fastify.get('/', async (req, reply) => {
|
|
305
|
-
reply.code(204)
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
fastify.inject({
|
|
309
|
-
method: 'GET',
|
|
310
|
-
url: '/'
|
|
311
|
-
}, (err, res) => {
|
|
312
|
-
t.error(err)
|
|
313
|
-
t.equal(res.statusCode, 204)
|
|
314
|
-
})
|
|
315
|
-
})
|
|
316
|
-
|
|
317
301
|
test('inject async await', async t => {
|
|
318
302
|
t.plan(1)
|
|
319
303
|
|
|
@@ -399,48 +383,8 @@ test('does not call reply.send() twice if 204 response equal already sent', t =>
|
|
|
399
383
|
})
|
|
400
384
|
})
|
|
401
385
|
|
|
402
|
-
test('
|
|
403
|
-
t.plan(
|
|
404
|
-
|
|
405
|
-
let fastify = null
|
|
406
|
-
const stream = split(JSON.parse)
|
|
407
|
-
try {
|
|
408
|
-
fastify = Fastify({
|
|
409
|
-
logger: {
|
|
410
|
-
stream,
|
|
411
|
-
level: 'error'
|
|
412
|
-
}
|
|
413
|
-
})
|
|
414
|
-
} catch (e) {
|
|
415
|
-
t.fail()
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
t.teardown(fastify.close.bind(fastify))
|
|
419
|
-
|
|
420
|
-
fastify.get('/', async (req, reply) => {
|
|
421
|
-
reply.code(200)
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
stream.once('data', line => {
|
|
425
|
-
t.equal(line.msg, 'Promise may not be fulfilled with \'undefined\' when statusCode is not 204')
|
|
426
|
-
})
|
|
427
|
-
|
|
428
|
-
fastify.listen(0, (err) => {
|
|
429
|
-
t.error(err)
|
|
430
|
-
fastify.server.unref()
|
|
431
|
-
|
|
432
|
-
sget({
|
|
433
|
-
method: 'GET',
|
|
434
|
-
url: 'http://localhost:' + fastify.server.address().port + '/',
|
|
435
|
-
timeout: 500
|
|
436
|
-
}, (err, res, body) => {
|
|
437
|
-
t.equal(err.message, 'Request timed out')
|
|
438
|
-
})
|
|
439
|
-
})
|
|
440
|
-
})
|
|
441
|
-
|
|
442
|
-
test('error is not logged because promise was fulfilled with undefined but statusCode 204 was set', t => {
|
|
443
|
-
t.plan(3)
|
|
386
|
+
test('promise was fulfilled with undefined', t => {
|
|
387
|
+
t.plan(4)
|
|
444
388
|
|
|
445
389
|
let fastify = null
|
|
446
390
|
const stream = split(JSON.parse)
|
|
@@ -458,7 +402,6 @@ test('error is not logged because promise was fulfilled with undefined but statu
|
|
|
458
402
|
t.teardown(fastify.close.bind(fastify))
|
|
459
403
|
|
|
460
404
|
fastify.get('/', async (req, reply) => {
|
|
461
|
-
reply.code(204)
|
|
462
405
|
})
|
|
463
406
|
|
|
464
407
|
stream.once('data', line => {
|
|
@@ -474,7 +417,8 @@ test('error is not logged because promise was fulfilled with undefined but statu
|
|
|
474
417
|
url: 'http://localhost:' + fastify.server.address().port + '/'
|
|
475
418
|
}, (err, res, body) => {
|
|
476
419
|
t.error(err)
|
|
477
|
-
t.equal(res.
|
|
420
|
+
t.equal(res.body, undefined)
|
|
421
|
+
t.equal(res.statusCode, 200)
|
|
478
422
|
})
|
|
479
423
|
})
|
|
480
424
|
})
|
|
@@ -601,7 +545,7 @@ test('customErrorHandler support without throwing', t => {
|
|
|
601
545
|
|
|
602
546
|
fastify.setErrorHandler(async (err, req, reply) => {
|
|
603
547
|
t.equal(err.message, 'ouch')
|
|
604
|
-
reply.code(401).send('kaboom')
|
|
548
|
+
await reply.code(401).send('kaboom')
|
|
605
549
|
reply.send = t.fail.bind(t, 'should not be called')
|
|
606
550
|
})
|
|
607
551
|
|
|
@@ -187,6 +187,38 @@ test('add', t => {
|
|
|
187
187
|
t.end()
|
|
188
188
|
})
|
|
189
189
|
|
|
190
|
+
test('non-Error thrown from content parser is properly handled', t => {
|
|
191
|
+
t.plan(3)
|
|
192
|
+
|
|
193
|
+
const fastify = Fastify()
|
|
194
|
+
|
|
195
|
+
const throwable = 'test'
|
|
196
|
+
const payload = 'error'
|
|
197
|
+
|
|
198
|
+
fastify.addContentTypeParser('text/test', (request, payload, done) => {
|
|
199
|
+
done(throwable)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
fastify.post('/', (req, reply) => {
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
fastify.setErrorHandler((err, req, res) => {
|
|
206
|
+
t.equal(err, throwable)
|
|
207
|
+
|
|
208
|
+
res.send(payload)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
fastify.inject({
|
|
212
|
+
method: 'POST',
|
|
213
|
+
url: '/',
|
|
214
|
+
headers: { 'Content-Type': 'text/test' },
|
|
215
|
+
body: 'some text'
|
|
216
|
+
}, (err, res) => {
|
|
217
|
+
t.error(err)
|
|
218
|
+
t.equal(res.payload, payload)
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
190
222
|
test('remove', t => {
|
|
191
223
|
test('should remove default parser', t => {
|
|
192
224
|
t.plan(2)
|
|
@@ -119,3 +119,55 @@ test('config with exposeHeadRoutes', t => {
|
|
|
119
119
|
t.same(JSON.parse(response.payload), { url: '/no-config', method: 'GET' })
|
|
120
120
|
})
|
|
121
121
|
})
|
|
122
|
+
|
|
123
|
+
test('config without exposeHeadRoutes', t => {
|
|
124
|
+
t.plan(9)
|
|
125
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
126
|
+
|
|
127
|
+
fastify.get('/get', {
|
|
128
|
+
schema: schema.schema,
|
|
129
|
+
config: Object.assign({}, schema.config)
|
|
130
|
+
}, handler)
|
|
131
|
+
|
|
132
|
+
fastify.route({
|
|
133
|
+
method: 'GET',
|
|
134
|
+
url: '/route',
|
|
135
|
+
schema: schema.schema,
|
|
136
|
+
handler,
|
|
137
|
+
config: Object.assign({}, schema.config)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
fastify.route({
|
|
141
|
+
method: 'GET',
|
|
142
|
+
url: '/no-config',
|
|
143
|
+
schema: schema.schema,
|
|
144
|
+
handler
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
fastify.inject({
|
|
148
|
+
method: 'GET',
|
|
149
|
+
url: '/get'
|
|
150
|
+
}, (err, response) => {
|
|
151
|
+
t.error(err)
|
|
152
|
+
t.equal(response.statusCode, 200)
|
|
153
|
+
t.same(JSON.parse(response.payload), Object.assign({ url: '/get', method: 'GET' }, schema.config))
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
fastify.inject({
|
|
157
|
+
method: 'GET',
|
|
158
|
+
url: '/route'
|
|
159
|
+
}, (err, response) => {
|
|
160
|
+
t.error(err)
|
|
161
|
+
t.equal(response.statusCode, 200)
|
|
162
|
+
t.same(JSON.parse(response.payload), Object.assign({ url: '/route', method: 'GET' }, schema.config))
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
fastify.inject({
|
|
166
|
+
method: 'GET',
|
|
167
|
+
url: '/no-config'
|
|
168
|
+
}, (err, response) => {
|
|
169
|
+
t.error(err)
|
|
170
|
+
t.equal(response.statusCode, 200)
|
|
171
|
+
t.same(JSON.parse(response.payload), { url: '/no-config', method: 'GET' })
|
|
172
|
+
})
|
|
173
|
+
})
|
|
@@ -5,12 +5,15 @@ const test = t.test
|
|
|
5
5
|
const Fastify = require('..')
|
|
6
6
|
const http = require('http')
|
|
7
7
|
const sget = require('simple-get').concat
|
|
8
|
+
const dns = require('dns').promises
|
|
8
9
|
|
|
9
|
-
test('Should support a custom http server', t => {
|
|
10
|
-
|
|
10
|
+
test('Should support a custom http server', async t => {
|
|
11
|
+
const localAddresses = await dns.lookup('localhost', { all: true })
|
|
12
|
+
|
|
13
|
+
t.plan(localAddresses.length + 3)
|
|
11
14
|
|
|
12
15
|
const serverFactory = (handler, opts) => {
|
|
13
|
-
t.ok(opts.serverFactory)
|
|
16
|
+
t.ok(opts.serverFactory, 'it is called twice for every HOST interface')
|
|
14
17
|
|
|
15
18
|
const server = http.createServer((req, res) => {
|
|
16
19
|
req.custom = true
|
|
@@ -29,16 +32,20 @@ test('Should support a custom http server', t => {
|
|
|
29
32
|
reply.send({ hello: 'world' })
|
|
30
33
|
})
|
|
31
34
|
|
|
32
|
-
fastify.listen(0
|
|
33
|
-
t.error(err)
|
|
35
|
+
await fastify.listen(0)
|
|
34
36
|
|
|
37
|
+
await new Promise((resolve, reject) => {
|
|
35
38
|
sget({
|
|
36
39
|
method: 'GET',
|
|
37
|
-
url: 'http://localhost:' + fastify.server.address().port
|
|
40
|
+
url: 'http://localhost:' + fastify.server.address().port,
|
|
41
|
+
rejectUnauthorized: false
|
|
38
42
|
}, (err, response, body) => {
|
|
39
|
-
|
|
43
|
+
if (err) {
|
|
44
|
+
return reject(err)
|
|
45
|
+
}
|
|
40
46
|
t.equal(response.statusCode, 200)
|
|
41
47
|
t.same(JSON.parse(body), { hello: 'world' })
|
|
48
|
+
resolve()
|
|
42
49
|
})
|
|
43
50
|
})
|
|
44
51
|
})
|
|
@@ -64,68 +64,3 @@ test('contentTypeParser should add a custom async parser', t => {
|
|
|
64
64
|
})
|
|
65
65
|
})
|
|
66
66
|
})
|
|
67
|
-
|
|
68
|
-
test('contentTypeParser should add a custom async parser - deprecated syntax', t => {
|
|
69
|
-
t.plan(5)
|
|
70
|
-
const fastify = Fastify()
|
|
71
|
-
|
|
72
|
-
process.on('warning', onWarning)
|
|
73
|
-
function onWarning (warning) {
|
|
74
|
-
t.equal(warning.name, 'FastifyDeprecation')
|
|
75
|
-
t.equal(warning.code, 'FSTDEP003')
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
fastify.post('/', (req, reply) => {
|
|
79
|
-
reply.send(req.body)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
fastify.options('/', (req, reply) => {
|
|
83
|
-
reply.send(req.body)
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
fastify.addContentTypeParser('application/jsoff', async function (req) {
|
|
87
|
-
const res = await new Promise((resolve, reject) => resolve(req))
|
|
88
|
-
return res
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
fastify.listen(0, err => {
|
|
92
|
-
t.error(err)
|
|
93
|
-
|
|
94
|
-
t.teardown(() => fastify.close())
|
|
95
|
-
|
|
96
|
-
t.test('in POST', t => {
|
|
97
|
-
t.plan(3)
|
|
98
|
-
|
|
99
|
-
sget({
|
|
100
|
-
method: 'POST',
|
|
101
|
-
url: 'http://localhost:' + fastify.server.address().port,
|
|
102
|
-
body: '{"hello":"world"}',
|
|
103
|
-
headers: {
|
|
104
|
-
'Content-Type': 'application/jsoff'
|
|
105
|
-
}
|
|
106
|
-
}, (err, response, body) => {
|
|
107
|
-
t.error(err)
|
|
108
|
-
t.equal(response.statusCode, 200)
|
|
109
|
-
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
t.test('in OPTIONS', t => {
|
|
114
|
-
t.plan(3)
|
|
115
|
-
|
|
116
|
-
sget({
|
|
117
|
-
method: 'OPTIONS',
|
|
118
|
-
url: 'http://localhost:' + fastify.server.address().port,
|
|
119
|
-
body: '{"hello":"world"}',
|
|
120
|
-
headers: {
|
|
121
|
-
'Content-Type': 'application/jsoff'
|
|
122
|
-
}
|
|
123
|
-
}, (err, response, body) => {
|
|
124
|
-
t.error(err)
|
|
125
|
-
t.equal(response.statusCode, 200)
|
|
126
|
-
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
|
127
|
-
process.removeListener('warning', onWarning)
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
})
|
|
131
|
-
})
|