fastify 4.16.3 → 4.18.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/GOVERNANCE.md +2 -2
- package/README.md +13 -10
- package/docs/Guides/Ecosystem.md +6 -0
- package/docs/Guides/Serverless.md +12 -1
- package/docs/Reference/Errors.md +5 -0
- package/docs/Reference/LTS.md +5 -5
- package/docs/Reference/Lifecycle.md +3 -0
- package/docs/Reference/Logging.md +34 -1
- package/docs/Reference/Reply.md +19 -0
- package/docs/Reference/Request.md +1 -1
- package/docs/Reference/Server.md +20 -2
- package/docs/Reference/Validation-and-Serialization.md +3 -2
- package/examples/benchmark/body.json +3 -0
- package/fastify.d.ts +6 -1
- package/fastify.js +18 -13
- package/lib/contentTypeParser.js +3 -1
- package/lib/errors.js +5 -0
- package/lib/handleRequest.js +15 -4
- package/lib/reply.js +3 -2
- package/lib/route.js +14 -3
- package/lib/schemas.js +18 -21
- package/lib/server.js +9 -4
- package/lib/validation.js +100 -16
- package/package.json +33 -33
- package/test/404s.test.js +4 -2
- package/test/custom-parser.0.test.js +777 -0
- package/test/{custom-parser.test.js → custom-parser.1.test.js} +1 -742
- package/test/delete.test.js +3 -0
- package/test/fastify-instance.test.js +39 -0
- package/test/fluent-schema.test.js +4 -4
- package/test/get.test.js +3 -0
- package/test/hooks-async.test.js +154 -0
- package/test/hooks.test.js +29 -29
- package/test/input-validation.js +10 -5
- package/test/internals/reply.test.js +114 -45
- package/test/internals/validation.test.js +58 -0
- package/test/reply-error.test.js +7 -7
- package/test/request-error.test.js +3 -0
- package/test/route-hooks.test.js +38 -0
- package/test/route.test.js +192 -74
- package/test/schema-examples.test.js +2 -0
- package/test/schema-serialization.test.js +7 -5
- package/test/schema-special-usage.test.js +569 -0
- package/test/schema-validation.test.js +8 -4
- package/test/search.test.js +3 -0
- package/test/types/fastify.test-d.ts +4 -1
- package/test/types/hooks.test-d.ts +42 -0
- package/test/types/instance.test-d.ts +1 -0
- package/test/types/logger.test-d.ts +10 -4
- package/test/types/reply.test-d.ts +4 -1
- package/test/types/route.test-d.ts +12 -0
- package/test/url-rewriting.test.js +3 -0
- package/test/validation-error-handling.test.js +18 -3
- package/types/.eslintrc.json +1 -1
- package/types/instance.d.ts +1 -1
- package/types/logger.d.ts +10 -1
- package/types/reply.d.ts +7 -1
- package/types/route.d.ts +11 -31
- package/types/type-provider.d.ts +0 -1
- package/types/utils.d.ts +3 -1
- /package/types/{tsconfig.json → tsconfig.eslint.json} +0 -0
package/test/route.test.js
CHANGED
|
@@ -8,7 +8,11 @@ const sget = require('simple-get').concat
|
|
|
8
8
|
const joi = require('joi')
|
|
9
9
|
const Fastify = require('..')
|
|
10
10
|
const proxyquire = require('proxyquire')
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
FST_ERR_INVALID_URL,
|
|
13
|
+
FST_ERR_INSTANCE_ALREADY_LISTENING,
|
|
14
|
+
FST_ERR_ROUTE_METHOD_INVALID
|
|
15
|
+
} = require('../lib/errors')
|
|
12
16
|
|
|
13
17
|
function getUrl (app) {
|
|
14
18
|
const { address, port } = app.server.address()
|
|
@@ -20,13 +24,14 @@ function getUrl (app) {
|
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
test('route', t => {
|
|
23
|
-
t.plan(
|
|
27
|
+
t.plan(10)
|
|
24
28
|
const test = t.test
|
|
25
|
-
const fastify = Fastify()
|
|
26
29
|
|
|
27
30
|
test('route - get', t => {
|
|
28
|
-
t.plan(
|
|
29
|
-
|
|
31
|
+
t.plan(4)
|
|
32
|
+
|
|
33
|
+
const fastify = Fastify()
|
|
34
|
+
t.doesNotThrow(() =>
|
|
30
35
|
fastify.route({
|
|
31
36
|
method: 'GET',
|
|
32
37
|
url: '/',
|
|
@@ -46,15 +51,27 @@ test('route', t => {
|
|
|
46
51
|
reply.send({ hello: 'world' })
|
|
47
52
|
}
|
|
48
53
|
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
57
|
+
if (err) t.error(err)
|
|
58
|
+
t.teardown(() => { fastify.close() })
|
|
59
|
+
sget({
|
|
60
|
+
method: 'GET',
|
|
61
|
+
url: getUrl(fastify) + '/'
|
|
62
|
+
}, (err, response, body) => {
|
|
63
|
+
t.error(err)
|
|
64
|
+
t.equal(response.statusCode, 200)
|
|
65
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
66
|
+
})
|
|
67
|
+
})
|
|
53
68
|
})
|
|
54
69
|
|
|
55
70
|
test('missing schema - route', t => {
|
|
56
|
-
t.plan(
|
|
57
|
-
|
|
71
|
+
t.plan(4)
|
|
72
|
+
|
|
73
|
+
const fastify = Fastify()
|
|
74
|
+
t.doesNotThrow(() =>
|
|
58
75
|
fastify.route({
|
|
59
76
|
method: 'GET',
|
|
60
77
|
url: '/missing',
|
|
@@ -62,106 +79,188 @@ test('route', t => {
|
|
|
62
79
|
reply.send({ hello: 'world' })
|
|
63
80
|
}
|
|
64
81
|
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
85
|
+
if (err) t.error(err)
|
|
86
|
+
t.teardown(() => { fastify.close() })
|
|
87
|
+
sget({
|
|
88
|
+
method: 'GET',
|
|
89
|
+
url: getUrl(fastify) + '/missing'
|
|
90
|
+
}, (err, response, body) => {
|
|
91
|
+
t.error(err)
|
|
92
|
+
t.equal(response.statusCode, 200)
|
|
93
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
94
|
+
})
|
|
95
|
+
})
|
|
69
96
|
})
|
|
70
97
|
|
|
71
98
|
test('invalid handler attribute - route', t => {
|
|
72
99
|
t.plan(1)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
} catch (e) {
|
|
77
|
-
t.pass()
|
|
78
|
-
}
|
|
100
|
+
|
|
101
|
+
const fastify = Fastify()
|
|
102
|
+
t.throws(() => fastify.get('/', { handler: 'not a function' }, () => { }))
|
|
79
103
|
})
|
|
80
104
|
|
|
81
|
-
test('Multiple methods', t => {
|
|
82
|
-
t.plan(
|
|
83
|
-
|
|
105
|
+
test('Add Multiple methods per route all uppercase', t => {
|
|
106
|
+
t.plan(7)
|
|
107
|
+
|
|
108
|
+
const fastify = Fastify()
|
|
109
|
+
t.doesNotThrow(() =>
|
|
84
110
|
fastify.route({
|
|
85
111
|
method: ['GET', 'DELETE'],
|
|
86
112
|
url: '/multiple',
|
|
87
113
|
handler: function (req, reply) {
|
|
88
114
|
reply.send({ hello: 'world' })
|
|
89
115
|
}
|
|
116
|
+
}))
|
|
117
|
+
|
|
118
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
119
|
+
if (err) t.error(err)
|
|
120
|
+
t.teardown(() => { fastify.close() })
|
|
121
|
+
sget({
|
|
122
|
+
method: 'GET',
|
|
123
|
+
url: getUrl(fastify) + '/multiple'
|
|
124
|
+
}, (err, response, body) => {
|
|
125
|
+
t.error(err)
|
|
126
|
+
t.equal(response.statusCode, 200)
|
|
127
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
90
128
|
})
|
|
91
|
-
t.pass()
|
|
92
|
-
} catch (e) {
|
|
93
|
-
t.fail()
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
129
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
130
|
+
sget({
|
|
131
|
+
method: 'DELETE',
|
|
132
|
+
url: getUrl(fastify) + '/multiple'
|
|
133
|
+
}, (err, response, body) => {
|
|
134
|
+
t.error(err)
|
|
135
|
+
t.equal(response.statusCode, 200)
|
|
136
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
102
137
|
})
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('Add Multiple methods per route all lowercase', t => {
|
|
142
|
+
t.plan(7)
|
|
143
|
+
|
|
144
|
+
const fastify = Fastify()
|
|
145
|
+
t.doesNotThrow(() =>
|
|
103
146
|
fastify.route({
|
|
104
|
-
method: ['
|
|
105
|
-
url: '/
|
|
147
|
+
method: ['get', 'delete'],
|
|
148
|
+
url: '/multiple',
|
|
106
149
|
handler: function (req, reply) {
|
|
107
150
|
reply.send({ hello: 'world' })
|
|
108
151
|
}
|
|
152
|
+
}))
|
|
153
|
+
|
|
154
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
155
|
+
if (err) t.error(err)
|
|
156
|
+
t.teardown(() => { fastify.close() })
|
|
157
|
+
sget({
|
|
158
|
+
method: 'GET',
|
|
159
|
+
url: getUrl(fastify) + '/multiple'
|
|
160
|
+
}, (err, response, body) => {
|
|
161
|
+
t.error(err)
|
|
162
|
+
t.equal(response.statusCode, 200)
|
|
163
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
109
164
|
})
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
165
|
+
|
|
166
|
+
sget({
|
|
167
|
+
method: 'DELETE',
|
|
168
|
+
url: getUrl(fastify) + '/multiple'
|
|
169
|
+
}, (err, response, body) => {
|
|
170
|
+
t.error(err)
|
|
171
|
+
t.equal(response.statusCode, 200)
|
|
172
|
+
t.same(JSON.parse(body), { hello: 'world' })
|
|
173
|
+
})
|
|
174
|
+
})
|
|
114
175
|
})
|
|
115
176
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
t.teardown(() => { fastify.close() })
|
|
177
|
+
test('Add Multiple methods per route mixed uppercase and lowercase', t => {
|
|
178
|
+
t.plan(7)
|
|
119
179
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
})
|
|
130
|
-
t.fail()
|
|
131
|
-
} catch (e) {
|
|
132
|
-
t.pass()
|
|
133
|
-
}
|
|
134
|
-
})
|
|
180
|
+
const fastify = Fastify()
|
|
181
|
+
t.doesNotThrow(() =>
|
|
182
|
+
fastify.route({
|
|
183
|
+
method: ['GET', 'delete'],
|
|
184
|
+
url: '/multiple',
|
|
185
|
+
handler: function (req, reply) {
|
|
186
|
+
reply.send({ hello: 'world' })
|
|
187
|
+
}
|
|
188
|
+
}))
|
|
135
189
|
|
|
136
|
-
|
|
137
|
-
t.
|
|
190
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
191
|
+
if (err) t.error(err)
|
|
192
|
+
t.teardown(() => { fastify.close() })
|
|
138
193
|
sget({
|
|
139
194
|
method: 'GET',
|
|
140
|
-
url:
|
|
195
|
+
url: getUrl(fastify) + '/multiple'
|
|
141
196
|
}, (err, response, body) => {
|
|
142
197
|
t.error(err)
|
|
143
198
|
t.equal(response.statusCode, 200)
|
|
144
199
|
t.same(JSON.parse(body), { hello: 'world' })
|
|
145
200
|
})
|
|
146
|
-
})
|
|
147
201
|
|
|
148
|
-
test('route - missing schema', t => {
|
|
149
|
-
t.plan(3)
|
|
150
202
|
sget({
|
|
151
|
-
method: '
|
|
152
|
-
url:
|
|
203
|
+
method: 'DELETE',
|
|
204
|
+
url: getUrl(fastify) + '/multiple'
|
|
153
205
|
}, (err, response, body) => {
|
|
154
206
|
t.error(err)
|
|
155
207
|
t.equal(response.statusCode, 200)
|
|
156
208
|
t.same(JSON.parse(body), { hello: 'world' })
|
|
157
209
|
})
|
|
158
210
|
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test('Add invalid Multiple methods per route', t => {
|
|
214
|
+
t.plan(1)
|
|
215
|
+
|
|
216
|
+
const fastify = Fastify()
|
|
217
|
+
t.throws(() =>
|
|
218
|
+
fastify.route({
|
|
219
|
+
method: ['GET', 1],
|
|
220
|
+
url: '/invalid-method',
|
|
221
|
+
handler: function (req, reply) {
|
|
222
|
+
reply.send({ hello: 'world' })
|
|
223
|
+
}
|
|
224
|
+
}), new FST_ERR_ROUTE_METHOD_INVALID())
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
test('Add method', t => {
|
|
228
|
+
t.plan(1)
|
|
159
229
|
|
|
160
|
-
|
|
161
|
-
|
|
230
|
+
const fastify = Fastify()
|
|
231
|
+
t.throws(() =>
|
|
232
|
+
fastify.route({
|
|
233
|
+
method: 1,
|
|
234
|
+
url: '/invalid-method',
|
|
235
|
+
handler: function (req, reply) {
|
|
236
|
+
reply.send({ hello: 'world' })
|
|
237
|
+
}
|
|
238
|
+
}), new FST_ERR_ROUTE_METHOD_INVALID())
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
test('Add additional multiple methods to existing route', t => {
|
|
242
|
+
t.plan(7)
|
|
243
|
+
|
|
244
|
+
const fastify = Fastify()
|
|
245
|
+
t.doesNotThrow(() => {
|
|
246
|
+
fastify.get('/add-multiple', function (req, reply) {
|
|
247
|
+
reply.send({ hello: 'Bob!' })
|
|
248
|
+
})
|
|
249
|
+
fastify.route({
|
|
250
|
+
method: ['PUT', 'DELETE'],
|
|
251
|
+
url: '/add-multiple',
|
|
252
|
+
handler: function (req, reply) {
|
|
253
|
+
reply.send({ hello: 'world' })
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
259
|
+
if (err) t.error(err)
|
|
260
|
+
t.teardown(() => { fastify.close() })
|
|
162
261
|
sget({
|
|
163
|
-
method: '
|
|
164
|
-
url:
|
|
262
|
+
method: 'PUT',
|
|
263
|
+
url: getUrl(fastify) + '/add-multiple'
|
|
165
264
|
}, (err, response, body) => {
|
|
166
265
|
t.error(err)
|
|
167
266
|
t.equal(response.statusCode, 200)
|
|
@@ -170,7 +269,7 @@ test('route', t => {
|
|
|
170
269
|
|
|
171
270
|
sget({
|
|
172
271
|
method: 'DELETE',
|
|
173
|
-
url:
|
|
272
|
+
url: getUrl(fastify) + '/add-multiple'
|
|
174
273
|
}, (err, response, body) => {
|
|
175
274
|
t.error(err)
|
|
176
275
|
t.equal(response.statusCode, 200)
|
|
@@ -178,6 +277,25 @@ test('route', t => {
|
|
|
178
277
|
})
|
|
179
278
|
})
|
|
180
279
|
})
|
|
280
|
+
|
|
281
|
+
test('cannot add another route after binding', t => {
|
|
282
|
+
t.plan(1)
|
|
283
|
+
|
|
284
|
+
const fastify = Fastify()
|
|
285
|
+
|
|
286
|
+
fastify.listen({ port: 0 }, function (err) {
|
|
287
|
+
if (err) t.error(err)
|
|
288
|
+
t.teardown(() => { fastify.close() })
|
|
289
|
+
|
|
290
|
+
t.throws(() => fastify.route({
|
|
291
|
+
method: 'GET',
|
|
292
|
+
url: '/another-get-route',
|
|
293
|
+
handler: function (req, reply) {
|
|
294
|
+
reply.send({ hello: 'world' })
|
|
295
|
+
}
|
|
296
|
+
}), new FST_ERR_INSTANCE_ALREADY_LISTENING('Cannot add route!'))
|
|
297
|
+
})
|
|
298
|
+
})
|
|
181
299
|
})
|
|
182
300
|
|
|
183
301
|
test('invalid schema - route', t => {
|
|
@@ -185,7 +303,7 @@ test('invalid schema - route', t => {
|
|
|
185
303
|
|
|
186
304
|
const fastify = Fastify()
|
|
187
305
|
fastify.route({
|
|
188
|
-
handler: () => {},
|
|
306
|
+
handler: () => { },
|
|
189
307
|
method: 'GET',
|
|
190
308
|
url: '/invalid',
|
|
191
309
|
schema: {
|
|
@@ -207,7 +325,7 @@ test('same route definition object on multiple prefixes', async t => {
|
|
|
207
325
|
t.plan(2)
|
|
208
326
|
|
|
209
327
|
const routeObject = {
|
|
210
|
-
handler: () => {},
|
|
328
|
+
handler: () => { },
|
|
211
329
|
method: 'GET',
|
|
212
330
|
url: '/simple'
|
|
213
331
|
}
|
|
@@ -1459,7 +1577,7 @@ test('invalid url attribute - non string URL', t => {
|
|
|
1459
1577
|
const fastify = Fastify()
|
|
1460
1578
|
|
|
1461
1579
|
try {
|
|
1462
|
-
fastify.get(/^\/(donations|skills|blogs)/, () => {})
|
|
1580
|
+
fastify.get(/^\/(donations|skills|blogs)/, () => { })
|
|
1463
1581
|
} catch (error) {
|
|
1464
1582
|
t.equal(error.code, FST_ERR_INVALID_URL().code)
|
|
1465
1583
|
}
|
|
@@ -502,6 +502,7 @@ test('should return custom error messages with ajv-errors', t => {
|
|
|
502
502
|
t.error(err)
|
|
503
503
|
t.same(JSON.parse(res.payload), {
|
|
504
504
|
statusCode: 400,
|
|
505
|
+
code: 'FST_ERR_VALIDATION',
|
|
505
506
|
error: 'Bad Request',
|
|
506
507
|
message: 'body/age bad age - should be num, body name please, body work please'
|
|
507
508
|
})
|
|
@@ -557,6 +558,7 @@ test('should be able to handle formats of ajv-formats when added by plugins opti
|
|
|
557
558
|
}, (_err, res) => {
|
|
558
559
|
t.same(JSON.parse(res.payload), {
|
|
559
560
|
statusCode: 400,
|
|
561
|
+
code: 'FST_ERR_VALIDATION',
|
|
560
562
|
error: 'Bad Request',
|
|
561
563
|
message: 'body/id must match format "uuid"'
|
|
562
564
|
})
|
|
@@ -394,7 +394,8 @@ test('Use shared schema and $ref with $id in response ($ref to $id)', t => {
|
|
|
394
394
|
t.same(res.json(), {
|
|
395
395
|
error: 'Bad Request',
|
|
396
396
|
message: "body must have required property 'address'",
|
|
397
|
-
statusCode: 400
|
|
397
|
+
statusCode: 400,
|
|
398
|
+
code: 'FST_ERR_VALIDATION'
|
|
398
399
|
})
|
|
399
400
|
})
|
|
400
401
|
})
|
|
@@ -503,7 +504,8 @@ test('Shared schema should be pass to serializer and validator ($ref to shared s
|
|
|
503
504
|
t.same(res.json(), {
|
|
504
505
|
error: 'Bad Request',
|
|
505
506
|
message: 'body/0/location/email must match format "email"',
|
|
506
|
-
statusCode: 400
|
|
507
|
+
statusCode: 400,
|
|
508
|
+
code: 'FST_ERR_VALIDATION'
|
|
507
509
|
})
|
|
508
510
|
})
|
|
509
511
|
})
|
|
@@ -806,9 +808,9 @@ test('do not crash if status code serializer errors', async t => {
|
|
|
806
808
|
const someUserErrorType2 = {
|
|
807
809
|
type: 'object',
|
|
808
810
|
properties: {
|
|
809
|
-
|
|
811
|
+
customCode: { type: 'number' }
|
|
810
812
|
},
|
|
811
|
-
required: ['
|
|
813
|
+
required: ['customCode']
|
|
812
814
|
}
|
|
813
815
|
|
|
814
816
|
fastify.get(
|
|
@@ -834,7 +836,7 @@ test('do not crash if status code serializer errors', async t => {
|
|
|
834
836
|
t.same(res.json(), {
|
|
835
837
|
statusCode: 500,
|
|
836
838
|
code: 'FST_ERR_FAILED_ERROR_SERIALIZATION',
|
|
837
|
-
message: 'Failed to serialize an error. Error: "
|
|
839
|
+
message: 'Failed to serialize an error. Error: "customCode" is required!. ' +
|
|
838
840
|
'Original error: querystring must have required property \'foo\''
|
|
839
841
|
})
|
|
840
842
|
})
|