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
|
@@ -163,7 +163,7 @@ test('Use shared schema and $ref with $id in response ($ref to $id)', t => {
|
|
|
163
163
|
t.equal(res.statusCode, 400)
|
|
164
164
|
t.same(res.json(), {
|
|
165
165
|
error: 'Bad Request',
|
|
166
|
-
message: "body
|
|
166
|
+
message: "body must have required property 'address'",
|
|
167
167
|
statusCode: 400
|
|
168
168
|
})
|
|
169
169
|
})
|
|
@@ -236,8 +236,7 @@ test('Shared schema should be pass to serializer and validator ($ref to shared s
|
|
|
236
236
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
237
237
|
title: 'List of Asset locations',
|
|
238
238
|
type: 'array',
|
|
239
|
-
items: { $ref: 'http://example.com/asset.json#' }
|
|
240
|
-
default: []
|
|
239
|
+
items: { $ref: 'http://example.com/asset.json#' }
|
|
241
240
|
}
|
|
242
241
|
|
|
243
242
|
fastify.post('/', {
|
|
@@ -273,7 +272,7 @@ test('Shared schema should be pass to serializer and validator ($ref to shared s
|
|
|
273
272
|
t.equal(res.statusCode, 400)
|
|
274
273
|
t.same(res.json(), {
|
|
275
274
|
error: 'Bad Request',
|
|
276
|
-
message: 'body
|
|
275
|
+
message: 'body/0/location/email must match format "email"',
|
|
277
276
|
statusCode: 400
|
|
278
277
|
})
|
|
279
278
|
})
|
|
@@ -282,7 +281,7 @@ test('Shared schema should be pass to serializer and validator ($ref to shared s
|
|
|
282
281
|
|
|
283
282
|
test('Custom setSerializerCompiler', t => {
|
|
284
283
|
t.plan(7)
|
|
285
|
-
const fastify = Fastify()
|
|
284
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
286
285
|
|
|
287
286
|
const outSchema = {
|
|
288
287
|
$id: 'test',
|
|
@@ -355,7 +354,6 @@ test('Custom setSerializerCompiler returns bad serialized output', t => {
|
|
|
355
354
|
t.error(err)
|
|
356
355
|
t.equal(res.statusCode, 500)
|
|
357
356
|
t.strictSame(res.json(), {
|
|
358
|
-
error: 'Internal Server Error',
|
|
359
357
|
code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE',
|
|
360
358
|
message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.',
|
|
361
359
|
statusCode: 500
|
|
@@ -410,11 +408,11 @@ test('Custom serializer per route', async t => {
|
|
|
410
408
|
res = await fastify.inject('/route')
|
|
411
409
|
t.equal(res.json().mean, 'route')
|
|
412
410
|
|
|
413
|
-
t.equal(hit,
|
|
411
|
+
t.equal(hit, 4, 'the custom and route serializer has been called')
|
|
414
412
|
})
|
|
415
413
|
|
|
416
414
|
test('Reply serializer win over serializer ', t => {
|
|
417
|
-
t.plan(
|
|
415
|
+
t.plan(6)
|
|
418
416
|
|
|
419
417
|
const fastify = Fastify()
|
|
420
418
|
fastify.setReplySerializer(function (payload, statusCode) {
|
|
@@ -453,7 +451,7 @@ test('Reply serializer win over serializer ', t => {
|
|
|
453
451
|
})
|
|
454
452
|
|
|
455
453
|
test('Reply serializer win over serializer ', t => {
|
|
456
|
-
t.plan(
|
|
454
|
+
t.plan(6)
|
|
457
455
|
|
|
458
456
|
const fastify = Fastify()
|
|
459
457
|
fastify.setReplySerializer(function (payload, statusCode) {
|
|
@@ -570,11 +568,13 @@ test('do not crash if status code serializer errors', async t => {
|
|
|
570
568
|
const fastify = Fastify()
|
|
571
569
|
|
|
572
570
|
const requiresFoo = {
|
|
571
|
+
type: 'object',
|
|
573
572
|
properties: { foo: { type: 'string' } },
|
|
574
573
|
required: ['foo']
|
|
575
574
|
}
|
|
576
575
|
|
|
577
576
|
const someUserErrorType2 = {
|
|
577
|
+
type: 'object',
|
|
578
578
|
properties: {
|
|
579
579
|
code: { type: 'number' }
|
|
580
580
|
},
|
|
@@ -1,167 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { test } = require('tap')
|
|
4
|
-
const Joi = require('
|
|
4
|
+
const Joi = require('joi')
|
|
5
5
|
const AJV = require('ajv')
|
|
6
6
|
const S = require('fluent-json-schema')
|
|
7
7
|
const Fastify = require('..')
|
|
8
8
|
const ajvMergePatch = require('ajv-merge-patch')
|
|
9
9
|
const ajvErrors = require('ajv-errors')
|
|
10
10
|
|
|
11
|
-
const buildValidatorAJV8 = require('@fastify/ajv-compiler-8')
|
|
12
|
-
|
|
13
|
-
test('Ajv8 usage instead of the bundle one', t => {
|
|
14
|
-
t.plan(2)
|
|
15
|
-
|
|
16
|
-
t.test('use new ajv8 option', t => {
|
|
17
|
-
t.plan(2)
|
|
18
|
-
const fastify = Fastify({
|
|
19
|
-
ajv: {
|
|
20
|
-
customOptions: { strictRequired: true }
|
|
21
|
-
},
|
|
22
|
-
schemaController: {
|
|
23
|
-
compilersFactory: {
|
|
24
|
-
buildValidator: buildValidatorAJV8()
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
fastify.post('/', {
|
|
30
|
-
schema: {
|
|
31
|
-
body: {
|
|
32
|
-
type: 'object',
|
|
33
|
-
required: ['missing'],
|
|
34
|
-
properties: {
|
|
35
|
-
foo: {
|
|
36
|
-
type: 'string'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
handler (req, reply) { reply.send({ ok: 1 }) }
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
fastify.ready(err => {
|
|
45
|
-
t.ok(err)
|
|
46
|
-
t.match(err.message, 'strictRequired', 'the new ajv8 option trigger a startup error')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
t.test('use new ajv8 option within a response schema', t => {
|
|
51
|
-
t.plan(2)
|
|
52
|
-
const fastify = Fastify({
|
|
53
|
-
schemaController: {
|
|
54
|
-
compilersFactory: {
|
|
55
|
-
buildValidator: buildValidatorAJV8()
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
fastify.post('/', {
|
|
61
|
-
schema: {
|
|
62
|
-
body: {
|
|
63
|
-
type: 'object',
|
|
64
|
-
required: ['missing'],
|
|
65
|
-
properties: {
|
|
66
|
-
foo: {
|
|
67
|
-
type: 'string'
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
response: {
|
|
72
|
-
'2xx': {
|
|
73
|
-
type: 'object',
|
|
74
|
-
properties: {
|
|
75
|
-
ok: {
|
|
76
|
-
type: 'integer'
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
handler (req, reply) { reply.send({ ok: 1 }) }
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
fastify.ready(err => {
|
|
86
|
-
t.error(err)
|
|
87
|
-
t.pass('startup successful')
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('Ajv8 usage with plugins', t => {
|
|
93
|
-
t.plan(2)
|
|
94
|
-
|
|
95
|
-
t.test('use new ajv8 option', t => {
|
|
96
|
-
t.plan(3)
|
|
97
|
-
const fastify = Fastify({
|
|
98
|
-
ajv: {
|
|
99
|
-
customOptions: { validateFormats: true },
|
|
100
|
-
plugins: [require('ajv-formats')]
|
|
101
|
-
},
|
|
102
|
-
schemaController: {
|
|
103
|
-
compilersFactory: {
|
|
104
|
-
buildValidator: buildValidatorAJV8()
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
callIt(fastify, (err, res) => {
|
|
110
|
-
t.error(err)
|
|
111
|
-
t.equal(res.statusCode, 400)
|
|
112
|
-
t.equal(res.json().message, 'body must match format "date"')
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
t.test('use new ajv8 option - avoid check', t => {
|
|
117
|
-
t.plan(2)
|
|
118
|
-
const fastify = Fastify({
|
|
119
|
-
ajv: {
|
|
120
|
-
customOptions: { validateFormats: false }
|
|
121
|
-
},
|
|
122
|
-
schemaController: {
|
|
123
|
-
compilersFactory: {
|
|
124
|
-
buildValidator: buildValidatorAJV8()
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
callIt(fastify, (err, res) => {
|
|
130
|
-
t.error(err)
|
|
131
|
-
t.equal(res.statusCode, 200)
|
|
132
|
-
})
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
function callIt (fastify, cb) {
|
|
136
|
-
fastify.post('/', {
|
|
137
|
-
schema: {
|
|
138
|
-
body: {
|
|
139
|
-
type: 'object',
|
|
140
|
-
properties: {
|
|
141
|
-
foo: {
|
|
142
|
-
type: 'string',
|
|
143
|
-
format: 'date'
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
handler (req, reply) { reply.send({ ok: 1 }) }
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
fastify.inject({
|
|
152
|
-
method: 'POST',
|
|
153
|
-
url: '/',
|
|
154
|
-
payload: { foo: '99' }
|
|
155
|
-
}, cb)
|
|
156
|
-
}
|
|
157
|
-
})
|
|
158
|
-
|
|
159
11
|
test('Ajv plugins array parameter', t => {
|
|
160
12
|
t.plan(3)
|
|
161
13
|
const fastify = Fastify({
|
|
162
14
|
ajv: {
|
|
163
15
|
customOptions: {
|
|
164
|
-
jsonPointers: true,
|
|
165
16
|
allErrors: true
|
|
166
17
|
},
|
|
167
18
|
plugins: [
|
|
@@ -509,7 +360,7 @@ test('setSchemaController in a plugin', t => {
|
|
|
509
360
|
ajvInstance.addSchema(baseSchema)
|
|
510
361
|
ajvInstance.addSchema(refSchema)
|
|
511
362
|
|
|
512
|
-
const fastify = Fastify()
|
|
363
|
+
const fastify = Fastify({ exposeHeadRoutes: false })
|
|
513
364
|
fastify.register(schemaPlugin)
|
|
514
365
|
fastify.get('/', {
|
|
515
366
|
schema: {
|
|
@@ -760,7 +611,8 @@ test('multiple refs with the same ids', t => {
|
|
|
760
611
|
|
|
761
612
|
fastify.addSchema(baseSchema)
|
|
762
613
|
fastify.addSchema(refSchema)
|
|
763
|
-
|
|
614
|
+
|
|
615
|
+
fastify.head('/', {
|
|
764
616
|
schema: {
|
|
765
617
|
query: refSchema,
|
|
766
618
|
response: {
|
|
@@ -772,7 +624,7 @@ test('multiple refs with the same ids', t => {
|
|
|
772
624
|
}
|
|
773
625
|
})
|
|
774
626
|
|
|
775
|
-
fastify.
|
|
627
|
+
fastify.get('/', {
|
|
776
628
|
schema: {
|
|
777
629
|
query: refSchema,
|
|
778
630
|
response: {
|
|
@@ -99,7 +99,7 @@ test('Basic validation test', t => {
|
|
|
99
99
|
url: '/'
|
|
100
100
|
}, (err, res) => {
|
|
101
101
|
t.error(err)
|
|
102
|
-
t.same(res.json(), { statusCode: 400, error: 'Bad Request', message: "body
|
|
102
|
+
t.same(res.json(), { statusCode: 400, error: 'Bad Request', message: "body must have required property 'work'" })
|
|
103
103
|
t.equal(res.statusCode, 400)
|
|
104
104
|
})
|
|
105
105
|
})
|
|
@@ -314,7 +314,7 @@ test('Triple $ref with a simple $id', t => {
|
|
|
314
314
|
}, (err, res) => {
|
|
315
315
|
t.error(err)
|
|
316
316
|
t.equal(res.statusCode, 400)
|
|
317
|
-
t.same(res.json().message, "body
|
|
317
|
+
t.same(res.json().message, "body must have required property 'foo'")
|
|
318
318
|
})
|
|
319
319
|
})
|
|
320
320
|
|
|
@@ -348,6 +348,7 @@ test('Extending schema', t => {
|
|
|
348
348
|
allOf: [
|
|
349
349
|
{ $ref: 'address.id#/definitions/address' },
|
|
350
350
|
{
|
|
351
|
+
type: 'object',
|
|
351
352
|
properties: { type: { enum: ['residential', 'business'] } },
|
|
352
353
|
required: ['type']
|
|
353
354
|
}
|
|
@@ -439,7 +440,7 @@ test('Should work with nested ids', t => {
|
|
|
439
440
|
}, (err, res) => {
|
|
440
441
|
t.error(err)
|
|
441
442
|
t.equal(res.statusCode, 400)
|
|
442
|
-
t.equal(res.json().message, 'params
|
|
443
|
+
t.equal(res.json().message, 'params/id must be number')
|
|
443
444
|
})
|
|
444
445
|
})
|
|
445
446
|
|
|
@@ -536,7 +537,7 @@ test('JSON Schema validation keywords', t => {
|
|
|
536
537
|
t.same(res.json(), {
|
|
537
538
|
statusCode: 400,
|
|
538
539
|
error: 'Bad Request',
|
|
539
|
-
message: 'params
|
|
540
|
+
message: 'params/ip must match format "ipv4"'
|
|
540
541
|
})
|
|
541
542
|
})
|
|
542
543
|
})
|
|
@@ -590,7 +591,7 @@ test('Nested id calls', t => {
|
|
|
590
591
|
t.equal(res.statusCode, 400)
|
|
591
592
|
t.same(res.json(), {
|
|
592
593
|
error: 'Bad Request',
|
|
593
|
-
message: 'body
|
|
594
|
+
message: 'body/host/ip must match format "ipv4"',
|
|
594
595
|
statusCode: 400
|
|
595
596
|
})
|
|
596
597
|
})
|
|
@@ -692,7 +693,7 @@ test('Use shared schema and $ref with $id ($ref to $id)', t => {
|
|
|
692
693
|
t.equal(res.statusCode, 400)
|
|
693
694
|
t.same(res.json(), {
|
|
694
695
|
error: 'Bad Request',
|
|
695
|
-
message: "body
|
|
696
|
+
message: "body must have required property 'address'",
|
|
696
697
|
statusCode: 400
|
|
697
698
|
})
|
|
698
699
|
})
|
|
@@ -712,8 +713,7 @@ test('Use items with $ref', t => {
|
|
|
712
713
|
|
|
713
714
|
const body = {
|
|
714
715
|
type: 'array',
|
|
715
|
-
items: { $ref: 'http://example.com/ref-to-external-validator.json#' }
|
|
716
|
-
default: []
|
|
716
|
+
items: { $ref: 'http://example.com/ref-to-external-validator.json#' }
|
|
717
717
|
}
|
|
718
718
|
|
|
719
719
|
fastify.post('/', {
|
|
@@ -809,7 +809,7 @@ test('Use $ref to /definitions', t => {
|
|
|
809
809
|
t.equal(res.statusCode, 400)
|
|
810
810
|
t.same(res.json(), {
|
|
811
811
|
error: 'Bad Request',
|
|
812
|
-
message: 'body
|
|
812
|
+
message: 'body/test/id must be number',
|
|
813
813
|
statusCode: 400
|
|
814
814
|
})
|
|
815
815
|
})
|
|
@@ -201,7 +201,7 @@ function testHandlerOrBeforeHandlerHook (test, hookOrHandler) {
|
|
|
201
201
|
|
|
202
202
|
nextHooks.forEach(h => app.addHook(h, async (req, reply) => t.fail(`${h} should not be called`)))
|
|
203
203
|
|
|
204
|
-
app.listen(0, err => {
|
|
204
|
+
app.listen({ port: 0 }, err => {
|
|
205
205
|
t.error(err)
|
|
206
206
|
const client = net.createConnection({ port: (app.server.address()).port }, () => {
|
|
207
207
|
client.write('GET / HTTP/1.1\r\n\r\n')
|
|
@@ -297,7 +297,7 @@ function testHandlerOrBeforeHandlerHook (test, hookOrHandler) {
|
|
|
297
297
|
} else {
|
|
298
298
|
app.addHook(hookOrHandler, async (req, reply) => {
|
|
299
299
|
reply.hijack()
|
|
300
|
-
reply.send('hello from reply.send()')
|
|
300
|
+
return reply.send('hello from reply.send()')
|
|
301
301
|
})
|
|
302
302
|
app.get('/', (req, reply) => t.fail('Handler should not be called'))
|
|
303
303
|
}
|
package/test/stream.test.js
CHANGED
|
@@ -14,7 +14,8 @@ const JSONStream = require('JSONStream')
|
|
|
14
14
|
const send = require('send')
|
|
15
15
|
const Readable = require('stream').Readable
|
|
16
16
|
const split = require('split2')
|
|
17
|
-
const
|
|
17
|
+
const semver = require('semver')
|
|
18
|
+
const { kDisableRequestLogging } = require('../lib/symbols.js')
|
|
18
19
|
|
|
19
20
|
function getUrl (app) {
|
|
20
21
|
const { address, port } = app.server.address()
|
|
@@ -26,7 +27,7 @@ function getUrl (app) {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
test('should respond with a stream', t => {
|
|
29
|
-
t.plan(
|
|
30
|
+
t.plan(6)
|
|
30
31
|
const fastify = Fastify()
|
|
31
32
|
|
|
32
33
|
fastify.get('/', function (req, reply) {
|
|
@@ -34,18 +35,13 @@ test('should respond with a stream', t => {
|
|
|
34
35
|
reply.code(200).send(stream)
|
|
35
36
|
})
|
|
36
37
|
|
|
37
|
-
fastify.
|
|
38
|
-
const stream = fs.createReadStream('not-existing-file', 'utf8')
|
|
39
|
-
reply.code(200).send(stream)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
fastify.listen(0, err => {
|
|
38
|
+
fastify.listen({ port: 0 }, err => {
|
|
43
39
|
t.error(err)
|
|
44
40
|
fastify.server.unref()
|
|
45
41
|
|
|
46
42
|
sget(`http://localhost:${fastify.server.address().port}`, function (err, response, data) {
|
|
47
43
|
t.error(err)
|
|
48
|
-
t.equal(response.headers['content-type'],
|
|
44
|
+
t.equal(response.headers['content-type'], undefined)
|
|
49
45
|
t.equal(response.statusCode, 200)
|
|
50
46
|
|
|
51
47
|
fs.readFile(__filename, (err, expected) => {
|
|
@@ -53,6 +49,21 @@ test('should respond with a stream', t => {
|
|
|
53
49
|
t.equal(expected.toString(), data.toString())
|
|
54
50
|
})
|
|
55
51
|
})
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('should respond with a stream (error)', t => {
|
|
56
|
+
t.plan(3)
|
|
57
|
+
const fastify = Fastify()
|
|
58
|
+
|
|
59
|
+
fastify.get('/error', function (req, reply) {
|
|
60
|
+
const stream = fs.createReadStream('not-existing-file', 'utf8')
|
|
61
|
+
reply.code(200).send(stream)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
fastify.listen({ port: 0 }, err => {
|
|
65
|
+
t.error(err)
|
|
66
|
+
fastify.server.unref()
|
|
56
67
|
|
|
57
68
|
sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
|
|
58
69
|
t.error(err)
|
|
@@ -105,7 +116,7 @@ test('should trigger the onSend hook only twice if pumping the stream fails, fir
|
|
|
105
116
|
done()
|
|
106
117
|
})
|
|
107
118
|
|
|
108
|
-
fastify.listen(0, err => {
|
|
119
|
+
fastify.listen({ port: 0 }, err => {
|
|
109
120
|
t.error(err)
|
|
110
121
|
|
|
111
122
|
fastify.server.unref()
|
|
@@ -268,7 +279,7 @@ test('Destroying streams prematurely', t => {
|
|
|
268
279
|
reply.send(reallyLongStream)
|
|
269
280
|
})
|
|
270
281
|
|
|
271
|
-
fastify.listen(0, err => {
|
|
282
|
+
fastify.listen({ port: 0 }, err => {
|
|
272
283
|
t.error(err)
|
|
273
284
|
fastify.server.unref()
|
|
274
285
|
|
|
@@ -331,7 +342,7 @@ test('Destroying streams prematurely should call close method', t => {
|
|
|
331
342
|
reply.send(reallyLongStream)
|
|
332
343
|
})
|
|
333
344
|
|
|
334
|
-
fastify.listen(0, err => {
|
|
345
|
+
fastify.listen({ port: 0 }, err => {
|
|
335
346
|
t.error(err)
|
|
336
347
|
fastify.server.unref()
|
|
337
348
|
|
|
@@ -393,7 +404,7 @@ test('Destroying streams prematurely should call close method when destroy is no
|
|
|
393
404
|
reply.send(reallyLongStream)
|
|
394
405
|
})
|
|
395
406
|
|
|
396
|
-
fastify.listen(0, err => {
|
|
407
|
+
fastify.listen({ port: 0 }, err => {
|
|
397
408
|
t.error(err)
|
|
398
409
|
fastify.server.unref()
|
|
399
410
|
|
|
@@ -456,7 +467,7 @@ test('Destroying streams prematurely should call abort method', t => {
|
|
|
456
467
|
reply.send(reallyLongStream)
|
|
457
468
|
})
|
|
458
469
|
|
|
459
|
-
fastify.listen(0, err => {
|
|
470
|
+
fastify.listen({ port: 0 }, err => {
|
|
460
471
|
t.error(err)
|
|
461
472
|
fastify.server.unref()
|
|
462
473
|
|
|
@@ -506,7 +517,7 @@ test('Destroying streams prematurely, log is disabled', t => {
|
|
|
506
517
|
reply.send(reallyLongStream)
|
|
507
518
|
})
|
|
508
519
|
|
|
509
|
-
fastify.listen(0, err => {
|
|
520
|
+
fastify.listen({ port: 0 }, err => {
|
|
510
521
|
t.error(err)
|
|
511
522
|
fastify.server.unref()
|
|
512
523
|
|
|
@@ -536,7 +547,7 @@ test('should respond with a stream1', t => {
|
|
|
536
547
|
stream.end({ a: 42 })
|
|
537
548
|
})
|
|
538
549
|
|
|
539
|
-
fastify.listen(0, err => {
|
|
550
|
+
fastify.listen({ port: 0 }, err => {
|
|
540
551
|
t.error(err)
|
|
541
552
|
fastify.server.unref()
|
|
542
553
|
|
|
@@ -568,7 +579,7 @@ test('return a 404 if the stream emits a 404 error', t => {
|
|
|
568
579
|
reply.send(reallyLongStream)
|
|
569
580
|
})
|
|
570
581
|
|
|
571
|
-
fastify.listen(0, err => {
|
|
582
|
+
fastify.listen({ port: 0 }, err => {
|
|
572
583
|
t.error(err)
|
|
573
584
|
fastify.server.unref()
|
|
574
585
|
|
|
@@ -582,7 +593,7 @@ test('return a 404 if the stream emits a 404 error', t => {
|
|
|
582
593
|
})
|
|
583
594
|
})
|
|
584
595
|
|
|
585
|
-
test('should support send module 200 and 404', {
|
|
596
|
+
test('should support send module 200 and 404', { skip: semver.gte(process.versions.node, '17.0.0') }, t => {
|
|
586
597
|
t.plan(8)
|
|
587
598
|
const fastify = Fastify()
|
|
588
599
|
|
|
@@ -596,7 +607,7 @@ test('should support send module 200 and 404', { only: true }, t => {
|
|
|
596
607
|
reply.code(200).send(stream)
|
|
597
608
|
})
|
|
598
609
|
|
|
599
|
-
fastify.listen(0, err => {
|
|
610
|
+
fastify.listen({ port: 0 }, err => {
|
|
600
611
|
t.error(err)
|
|
601
612
|
fastify.server.unref()
|
|
602
613
|
|
|
@@ -604,7 +615,7 @@ test('should support send module 200 and 404', { only: true }, t => {
|
|
|
604
615
|
|
|
605
616
|
sget(url, function (err, response, data) {
|
|
606
617
|
t.error(err)
|
|
607
|
-
t.equal(response.headers['content-type'], 'application/
|
|
618
|
+
t.equal(response.headers['content-type'], 'application/javascript; charset=UTF-8')
|
|
608
619
|
t.equal(response.statusCode, 200)
|
|
609
620
|
|
|
610
621
|
fs.readFile(__filename, (err, expected) => {
|
|
@@ -637,7 +648,7 @@ test('should destroy stream when response is ended', t => {
|
|
|
637
648
|
reply.raw.end(Buffer.from('hello\n'))
|
|
638
649
|
})
|
|
639
650
|
|
|
640
|
-
fastify.listen(0, err => {
|
|
651
|
+
fastify.listen({ port: 0 }, err => {
|
|
641
652
|
t.error(err)
|
|
642
653
|
fastify.server.unref()
|
|
643
654
|
|
|
@@ -654,7 +665,7 @@ test('should mark reply as sent before pumping the payload stream into response
|
|
|
654
665
|
const handleRequest = proxyquire('../lib/handleRequest', {
|
|
655
666
|
'./wrapThenable': (thenable, reply) => {
|
|
656
667
|
thenable.then(function (payload) {
|
|
657
|
-
t.equal(reply
|
|
668
|
+
t.equal(reply.sent, true)
|
|
658
669
|
})
|
|
659
670
|
}
|
|
660
671
|
})
|
|
@@ -671,7 +682,7 @@ test('should mark reply as sent before pumping the payload stream into response
|
|
|
671
682
|
|
|
672
683
|
fastify.get('/', async function (req, reply) {
|
|
673
684
|
const stream = fs.createReadStream(__filename, 'utf8')
|
|
674
|
-
reply.code(200).send(stream)
|
|
685
|
+
return reply.code(200).send(stream)
|
|
675
686
|
})
|
|
676
687
|
|
|
677
688
|
fastify.inject({
|
|
@@ -683,3 +694,51 @@ test('should mark reply as sent before pumping the payload stream into response
|
|
|
683
694
|
fastify.close()
|
|
684
695
|
})
|
|
685
696
|
})
|
|
697
|
+
|
|
698
|
+
test('reply.send handles aborted requests', t => {
|
|
699
|
+
t.plan(2)
|
|
700
|
+
|
|
701
|
+
const spyLogger = {
|
|
702
|
+
level: 'error',
|
|
703
|
+
fatal: () => { },
|
|
704
|
+
error: () => {
|
|
705
|
+
t.fail('should not log an error')
|
|
706
|
+
},
|
|
707
|
+
warn: () => { },
|
|
708
|
+
info: () => { },
|
|
709
|
+
debug: () => { },
|
|
710
|
+
trace: () => { },
|
|
711
|
+
child: () => { return spyLogger }
|
|
712
|
+
}
|
|
713
|
+
const fastify = Fastify({
|
|
714
|
+
logger: spyLogger
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
fastify.get('/', (req, reply) => {
|
|
718
|
+
setTimeout(() => {
|
|
719
|
+
const stream = new Readable({
|
|
720
|
+
read: function () {
|
|
721
|
+
this.push(null)
|
|
722
|
+
}
|
|
723
|
+
})
|
|
724
|
+
reply.send(stream)
|
|
725
|
+
}, 6)
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
fastify.listen({ port: 0 }, err => {
|
|
729
|
+
t.error(err)
|
|
730
|
+
fastify.server.unref()
|
|
731
|
+
|
|
732
|
+
const port = fastify.server.address().port
|
|
733
|
+
const http = require('http')
|
|
734
|
+
const req = http.get(`http://localhost:${port}`)
|
|
735
|
+
.on('error', (err) => {
|
|
736
|
+
t.equal(err.code, 'ECONNRESET')
|
|
737
|
+
fastify.close()
|
|
738
|
+
})
|
|
739
|
+
|
|
740
|
+
setTimeout(() => {
|
|
741
|
+
req.abort()
|
|
742
|
+
}, 1)
|
|
743
|
+
})
|
|
744
|
+
})
|
package/test/throw.test.js
CHANGED
|
@@ -17,12 +17,15 @@ test('Fastify should throw on wrong options', t => {
|
|
|
17
17
|
test('Fastify should throw on multiple assignment to the same route', t => {
|
|
18
18
|
t.plan(1)
|
|
19
19
|
const fastify = Fastify()
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
fastify.get('/', () => {})
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
try {
|
|
24
|
+
fastify.get('/', () => {})
|
|
25
|
+
t.fail('Should throw on duplicated route declaration')
|
|
26
|
+
} catch (error) {
|
|
27
|
+
t.equal(error.message, "Method 'GET' already declared for route '/'")
|
|
28
|
+
}
|
|
26
29
|
})
|
|
27
30
|
|
|
28
31
|
test('Fastify should throw for an invalid schema, printing the error route - headers', t => {
|
|
@@ -78,7 +81,7 @@ test('Fastify should throw for an invalid shorthand option type', t => {
|
|
|
78
81
|
t.fail()
|
|
79
82
|
} catch (e) {
|
|
80
83
|
t.equal(e.code, 'FST_ERR_INIT_OPTS_INVALID')
|
|
81
|
-
t.match(e.message, /
|
|
84
|
+
t.match(e.message, /must be boolean/)
|
|
82
85
|
t.pass()
|
|
83
86
|
}
|
|
84
87
|
})
|
package/test/trust-proxy.test.js
CHANGED
|
@@ -63,7 +63,7 @@ test('trust proxy, not add properties to node req', (t) => {
|
|
|
63
63
|
|
|
64
64
|
t.teardown(app.close.bind(app))
|
|
65
65
|
|
|
66
|
-
app.listen(0, (err) => {
|
|
66
|
+
app.listen({ port: 0 }, (err) => {
|
|
67
67
|
app.server.unref()
|
|
68
68
|
t.error(err)
|
|
69
69
|
sgetForwardedRequest(app, '1.1.1.1', '/trustproxy')
|
|
@@ -84,7 +84,7 @@ test('trust proxy chain', (t) => {
|
|
|
84
84
|
|
|
85
85
|
t.teardown(app.close.bind(app))
|
|
86
86
|
|
|
87
|
-
app.listen(0, (err) => {
|
|
87
|
+
app.listen({ port: 0 }, (err) => {
|
|
88
88
|
app.server.unref()
|
|
89
89
|
t.error(err)
|
|
90
90
|
sgetForwardedRequest(app, '192.168.1.1, 1.1.1.1', '/trustproxychain')
|
|
@@ -103,7 +103,7 @@ test('trust proxy function', (t) => {
|
|
|
103
103
|
|
|
104
104
|
t.teardown(app.close.bind(app))
|
|
105
105
|
|
|
106
|
-
app.listen(0, (err) => {
|
|
106
|
+
app.listen({ port: 0 }, (err) => {
|
|
107
107
|
app.server.unref()
|
|
108
108
|
t.error(err)
|
|
109
109
|
sgetForwardedRequest(app, '1.1.1.1', '/trustproxyfunc')
|
|
@@ -122,7 +122,7 @@ test('trust proxy number', (t) => {
|
|
|
122
122
|
|
|
123
123
|
t.teardown(app.close.bind(app))
|
|
124
124
|
|
|
125
|
-
app.listen(0, (err) => {
|
|
125
|
+
app.listen({ port: 0 }, (err) => {
|
|
126
126
|
app.server.unref()
|
|
127
127
|
t.error(err)
|
|
128
128
|
sgetForwardedRequest(app, '2.2.2.2, 1.1.1.1', '/trustproxynumber')
|
|
@@ -141,7 +141,7 @@ test('trust proxy IP addresses', (t) => {
|
|
|
141
141
|
|
|
142
142
|
t.teardown(app.close.bind(app))
|
|
143
143
|
|
|
144
|
-
app.listen(0, (err) => {
|
|
144
|
+
app.listen({ port: 0 }, (err) => {
|
|
145
145
|
app.server.unref()
|
|
146
146
|
t.error(err)
|
|
147
147
|
sgetForwardedRequest(app, '3.3.3.3, 2.2.2.2, 1.1.1.1', '/trustproxyipaddrs')
|
|
@@ -168,7 +168,7 @@ test('trust proxy protocol', (t) => {
|
|
|
168
168
|
|
|
169
169
|
t.teardown(app.close.bind(app))
|
|
170
170
|
|
|
171
|
-
app.listen(0, (err) => {
|
|
171
|
+
app.listen({ port: 0 }, (err) => {
|
|
172
172
|
app.server.unref()
|
|
173
173
|
t.error(err)
|
|
174
174
|
sgetForwardedRequest(app, '1.1.1.1', '/trustproxyprotocol', 'lorem')
|