fastify 4.17.0 → 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.
Files changed (49) hide show
  1. package/GOVERNANCE.md +2 -2
  2. package/README.md +13 -10
  3. package/docs/Guides/Ecosystem.md +6 -0
  4. package/docs/Guides/Serverless.md +12 -1
  5. package/docs/Reference/Errors.md +5 -0
  6. package/docs/Reference/LTS.md +5 -5
  7. package/docs/Reference/Lifecycle.md +3 -0
  8. package/docs/Reference/Logging.md +34 -1
  9. package/docs/Reference/Reply.md +19 -0
  10. package/docs/Reference/Request.md +1 -1
  11. package/docs/Reference/Server.md +20 -2
  12. package/docs/Reference/Validation-and-Serialization.md +3 -2
  13. package/examples/benchmark/body.json +3 -0
  14. package/fastify.d.ts +6 -1
  15. package/fastify.js +17 -12
  16. package/lib/contentTypeParser.js +3 -1
  17. package/lib/errors.js +5 -0
  18. package/lib/handleRequest.js +15 -4
  19. package/lib/reply.js +3 -2
  20. package/lib/route.js +14 -3
  21. package/lib/schemas.js +18 -21
  22. package/lib/server.js +9 -4
  23. package/lib/validation.js +98 -16
  24. package/package.json +33 -33
  25. package/test/custom-parser.0.test.js +777 -0
  26. package/test/{custom-parser.test.js → custom-parser.1.test.js} +1 -742
  27. package/test/fastify-instance.test.js +39 -0
  28. package/test/hooks-async.test.js +154 -0
  29. package/test/hooks.test.js +29 -29
  30. package/test/internals/reply.test.js +114 -45
  31. package/test/internals/validation.test.js +58 -0
  32. package/test/reply-error.test.js +7 -7
  33. package/test/request-error.test.js +3 -0
  34. package/test/route-hooks.test.js +38 -0
  35. package/test/route.test.js +192 -74
  36. package/test/schema-special-usage.test.js +569 -0
  37. package/test/types/fastify.test-d.ts +4 -1
  38. package/test/types/instance.test-d.ts +1 -0
  39. package/test/types/logger.test-d.ts +10 -4
  40. package/test/types/reply.test-d.ts +4 -1
  41. package/test/types/route.test-d.ts +12 -0
  42. package/test/url-rewriting.test.js +3 -0
  43. package/types/.eslintrc.json +1 -1
  44. package/types/instance.d.ts +1 -1
  45. package/types/logger.d.ts +10 -1
  46. package/types/reply.d.ts +7 -1
  47. package/types/type-provider.d.ts +0 -1
  48. package/types/utils.d.ts +3 -1
  49. /package/types/{tsconfig.json → tsconfig.eslint.json} +0 -0
@@ -3,6 +3,8 @@
3
3
  const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
+ const os = require('os')
7
+
6
8
  const {
7
9
  kOptions,
8
10
  kErrorHandler
@@ -97,3 +99,40 @@ test('errorHandler in plugin should be separate from the external one', async t
97
99
  t.ok(fastify[kErrorHandler].func instanceof Function)
98
100
  t.same(fastify.errorHandler, fastify[kErrorHandler].func)
99
101
  })
102
+
103
+ test('fastify instance should contains listeningOrigin property (with port and host)', async t => {
104
+ t.plan(1)
105
+ const port = 3000
106
+ const host = '127.0.0.1'
107
+ const fastify = Fastify()
108
+ await fastify.listen({ port, host })
109
+ t.same(fastify.listeningOrigin, `http://${host}:${port}`)
110
+ await fastify.close()
111
+ })
112
+
113
+ test('fastify instance should contains listeningOrigin property (with port and https)', async t => {
114
+ t.plan(1)
115
+ const port = 3000
116
+ const host = '127.0.0.1'
117
+ const fastify = Fastify({ https: {} })
118
+ await fastify.listen({ port, host })
119
+ t.same(fastify.listeningOrigin, `https://${host}:${port}`)
120
+ await fastify.close()
121
+ })
122
+
123
+ test('fastify instance should contains listeningOrigin property (no options)', async t => {
124
+ t.plan(1)
125
+ const fastify = Fastify()
126
+ await fastify.listen()
127
+ const address = fastify.server.address()
128
+ t.same(fastify.listeningOrigin, `http://${address.address}:${address.port}`)
129
+ await fastify.close()
130
+ })
131
+
132
+ test('fastify instance should contains listeningOrigin property (unix socket)', { skip: os.platform() === 'win32' }, async t => {
133
+ const fastify = Fastify()
134
+ const path = `fastify.${Date.now()}.sock`
135
+ await fastify.listen({ path })
136
+ t.same(fastify.listeningOrigin, path)
137
+ await fastify.close()
138
+ })
@@ -194,6 +194,160 @@ test('preParsing hooks should be able to modify the payload', t => {
194
194
  })
195
195
  })
196
196
 
197
+ test('preParsing hooks should be able to supply statusCode', t => {
198
+ t.plan(4)
199
+ const fastify = Fastify()
200
+
201
+ fastify.addHook('preParsing', async (req, reply, payload) => {
202
+ const stream = new Readable({
203
+ read () {
204
+ const error = new Error('kaboom')
205
+ error.statusCode = 408
206
+ this.destroy(error)
207
+ }
208
+ })
209
+ stream.receivedEncodedLength = 20
210
+ return stream
211
+ })
212
+
213
+ fastify.addHook('onError', async (req, res, err) => {
214
+ t.equal(err.statusCode, 408)
215
+ })
216
+
217
+ fastify.post('/', function (request, reply) {
218
+ t.fail('should not be called')
219
+ })
220
+
221
+ fastify.inject({
222
+ method: 'POST',
223
+ url: '/',
224
+ payload: { hello: 'world' }
225
+ }, (err, res) => {
226
+ t.error(err)
227
+ t.equal(res.statusCode, 408)
228
+ t.same(JSON.parse(res.payload), {
229
+ statusCode: 408,
230
+ error: 'Request Timeout',
231
+ message: 'kaboom'
232
+ })
233
+ })
234
+ })
235
+
236
+ test('preParsing hooks should ignore statusCode 200 in stream error', t => {
237
+ t.plan(4)
238
+ const fastify = Fastify()
239
+
240
+ fastify.addHook('preParsing', async (req, reply, payload) => {
241
+ const stream = new Readable({
242
+ read () {
243
+ const error = new Error('kaboom')
244
+ error.statusCode = 200
245
+ this.destroy(error)
246
+ }
247
+ })
248
+ stream.receivedEncodedLength = 20
249
+ return stream
250
+ })
251
+
252
+ fastify.addHook('onError', async (req, res, err) => {
253
+ t.equal(err.statusCode, 400)
254
+ })
255
+
256
+ fastify.post('/', function (request, reply) {
257
+ t.fail('should not be called')
258
+ })
259
+
260
+ fastify.inject({
261
+ method: 'POST',
262
+ url: '/',
263
+ payload: { hello: 'world' }
264
+ }, (err, res) => {
265
+ t.error(err)
266
+ t.equal(res.statusCode, 400)
267
+ t.same(JSON.parse(res.payload), {
268
+ statusCode: 400,
269
+ error: 'Bad Request',
270
+ message: 'kaboom'
271
+ })
272
+ })
273
+ })
274
+
275
+ test('preParsing hooks should ignore non-number statusCode in stream error', t => {
276
+ t.plan(4)
277
+ const fastify = Fastify()
278
+
279
+ fastify.addHook('preParsing', async (req, reply, payload) => {
280
+ const stream = new Readable({
281
+ read () {
282
+ const error = new Error('kaboom')
283
+ error.statusCode = '418'
284
+ this.destroy(error)
285
+ }
286
+ })
287
+ stream.receivedEncodedLength = 20
288
+ return stream
289
+ })
290
+
291
+ fastify.addHook('onError', async (req, res, err) => {
292
+ t.equal(err.statusCode, 400)
293
+ })
294
+
295
+ fastify.post('/', function (request, reply) {
296
+ t.fail('should not be called')
297
+ })
298
+
299
+ fastify.inject({
300
+ method: 'POST',
301
+ url: '/',
302
+ payload: { hello: 'world' }
303
+ }, (err, res) => {
304
+ t.error(err)
305
+ t.equal(res.statusCode, 400)
306
+ t.same(JSON.parse(res.payload), {
307
+ statusCode: 400,
308
+ error: 'Bad Request',
309
+ message: 'kaboom'
310
+ })
311
+ })
312
+ })
313
+
314
+ test('preParsing hooks should default to statusCode 400 if stream error', t => {
315
+ t.plan(4)
316
+ const fastify = Fastify()
317
+
318
+ fastify.addHook('preParsing', async (req, reply, payload) => {
319
+ const stream = new Readable({
320
+ read () {
321
+ this.destroy(new Error('kaboom'))
322
+ }
323
+ })
324
+ stream.receivedEncodedLength = 20
325
+ return stream
326
+ })
327
+
328
+ fastify.addHook('onError', async (req, res, err) => {
329
+ t.equal(err.statusCode, 400)
330
+ })
331
+
332
+ fastify.post('/', function (request, reply) {
333
+ t.fail('should not be called')
334
+ })
335
+
336
+ fastify.inject({
337
+ method: 'POST',
338
+ url: '/',
339
+ payload: { hello: 'world' }
340
+ }, (err, res) => {
341
+ t.error(err)
342
+ t.equal(res.statusCode, 400)
343
+ t.same(JSON.parse(res.payload), {
344
+ statusCode: 400,
345
+ error: 'Bad Request',
346
+ message: 'kaboom'
347
+ })
348
+ })
349
+ })
350
+
197
351
  test('preParsing hooks should handle errors', t => {
198
352
  t.plan(3)
199
353
  const fastify = Fastify()
@@ -165,7 +165,7 @@ test('hooks', t => {
165
165
 
166
166
  sget({
167
167
  method: 'GET',
168
- url: 'http://localhost:' + fastify.server.address().port
168
+ url: 'http://127.0.0.1:' + fastify.server.address().port
169
169
  }, (err, response, body) => {
170
170
  t.error(err)
171
171
  t.equal(response.statusCode, 200)
@@ -175,7 +175,7 @@ test('hooks', t => {
175
175
 
176
176
  sget({
177
177
  method: 'HEAD',
178
- url: 'http://localhost:' + fastify.server.address().port
178
+ url: 'http://127.0.0.1:' + fastify.server.address().port
179
179
  }, (err, response, body) => {
180
180
  t.error(err)
181
181
  t.equal(response.statusCode, 500)
@@ -183,7 +183,7 @@ test('hooks', t => {
183
183
 
184
184
  sget({
185
185
  method: 'DELETE',
186
- url: 'http://localhost:' + fastify.server.address().port
186
+ url: 'http://127.0.0.1:' + fastify.server.address().port
187
187
  }, (err, response, body) => {
188
188
  t.error(err)
189
189
  t.equal(response.statusCode, 500)
@@ -288,7 +288,7 @@ test('onRequest hook should support encapsulation / 3', t => {
288
288
 
289
289
  sget({
290
290
  method: 'GET',
291
- url: 'http://localhost:' + fastify.server.address().port + '/first'
291
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
292
292
  }, (err, response, body) => {
293
293
  t.error(err)
294
294
  t.equal(response.statusCode, 200)
@@ -298,7 +298,7 @@ test('onRequest hook should support encapsulation / 3', t => {
298
298
 
299
299
  sget({
300
300
  method: 'GET',
301
- url: 'http://localhost:' + fastify.server.address().port + '/second'
301
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
302
302
  }, (err, response, body) => {
303
303
  t.error(err)
304
304
  t.equal(response.statusCode, 200)
@@ -349,7 +349,7 @@ test('preHandler hook should support encapsulation / 5', t => {
349
349
 
350
350
  sget({
351
351
  method: 'GET',
352
- url: 'http://localhost:' + fastify.server.address().port + '/first'
352
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
353
353
  }, (err, response, body) => {
354
354
  t.error(err)
355
355
  t.equal(response.statusCode, 200)
@@ -359,7 +359,7 @@ test('preHandler hook should support encapsulation / 5', t => {
359
359
 
360
360
  sget({
361
361
  method: 'GET',
362
- url: 'http://localhost:' + fastify.server.address().port + '/second'
362
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
363
363
  }, (err, response, body) => {
364
364
  t.error(err)
365
365
  t.equal(response.statusCode, 200)
@@ -966,7 +966,7 @@ test('onResponse hook should support encapsulation / 3', t => {
966
966
 
967
967
  sget({
968
968
  method: 'GET',
969
- url: 'http://localhost:' + fastify.server.address().port + '/first'
969
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
970
970
  }, (err, response, body) => {
971
971
  t.error(err)
972
972
  t.equal(response.statusCode, 200)
@@ -976,7 +976,7 @@ test('onResponse hook should support encapsulation / 3', t => {
976
976
 
977
977
  sget({
978
978
  method: 'GET',
979
- url: 'http://localhost:' + fastify.server.address().port + '/second'
979
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
980
980
  }, (err, response, body) => {
981
981
  t.error(err)
982
982
  t.equal(response.statusCode, 200)
@@ -1043,7 +1043,7 @@ test('onSend hook should support encapsulation / 2', t => {
1043
1043
 
1044
1044
  sget({
1045
1045
  method: 'GET',
1046
- url: 'http://localhost:' + fastify.server.address().port + '/first'
1046
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
1047
1047
  }, (err, response, body) => {
1048
1048
  t.error(err)
1049
1049
  t.equal(response.statusCode, 200)
@@ -1053,7 +1053,7 @@ test('onSend hook should support encapsulation / 2', t => {
1053
1053
 
1054
1054
  sget({
1055
1055
  method: 'GET',
1056
- url: 'http://localhost:' + fastify.server.address().port + '/second'
1056
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
1057
1057
  }, (err, response, body) => {
1058
1058
  t.error(err)
1059
1059
  t.equal(response.statusCode, 200)
@@ -1338,7 +1338,7 @@ test('onSend hook throws', t => {
1338
1338
 
1339
1339
  sget({
1340
1340
  method: 'GET',
1341
- url: 'http://localhost:' + fastify.server.address().port
1341
+ url: 'http://127.0.0.1:' + fastify.server.address().port
1342
1342
  }, (err, response, body) => {
1343
1343
  t.error(err)
1344
1344
  t.equal(response.statusCode, 200)
@@ -1347,21 +1347,21 @@ test('onSend hook throws', t => {
1347
1347
  })
1348
1348
  sget({
1349
1349
  method: 'POST',
1350
- url: 'http://localhost:' + fastify.server.address().port
1350
+ url: 'http://127.0.0.1:' + fastify.server.address().port
1351
1351
  }, (err, response, body) => {
1352
1352
  t.error(err)
1353
1353
  t.equal(response.statusCode, 500)
1354
1354
  })
1355
1355
  sget({
1356
1356
  method: 'DELETE',
1357
- url: 'http://localhost:' + fastify.server.address().port
1357
+ url: 'http://127.0.0.1:' + fastify.server.address().port
1358
1358
  }, (err, response, body) => {
1359
1359
  t.error(err)
1360
1360
  t.equal(response.statusCode, 500)
1361
1361
  })
1362
1362
  sget({
1363
1363
  method: 'PUT',
1364
- url: 'http://localhost:' + fastify.server.address().port
1364
+ url: 'http://127.0.0.1:' + fastify.server.address().port
1365
1365
  }, (err, response, body) => {
1366
1366
  t.error(err)
1367
1367
  t.equal(response.statusCode, 500)
@@ -2476,7 +2476,7 @@ test('preValidation hook should support encapsulation / 3', t => {
2476
2476
 
2477
2477
  sget({
2478
2478
  method: 'GET',
2479
- url: 'http://localhost:' + fastify.server.address().port + '/first'
2479
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
2480
2480
  }, (err, response, body) => {
2481
2481
  t.error(err)
2482
2482
  t.equal(response.statusCode, 200)
@@ -2486,7 +2486,7 @@ test('preValidation hook should support encapsulation / 3', t => {
2486
2486
 
2487
2487
  sget({
2488
2488
  method: 'GET',
2489
- url: 'http://localhost:' + fastify.server.address().port + '/second'
2489
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
2490
2490
  }, (err, response, body) => {
2491
2491
  t.error(err)
2492
2492
  t.equal(response.statusCode, 200)
@@ -2623,7 +2623,7 @@ test('preParsing hook should run before parsing and be able to modify the payloa
2623
2623
 
2624
2624
  sget({
2625
2625
  method: 'POST',
2626
- url: 'http://localhost:' + fastify.server.address().port + '/first',
2626
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first',
2627
2627
  body: { hello: 'world' },
2628
2628
  json: true
2629
2629
  }, (err, response, body) => {
@@ -2666,7 +2666,7 @@ test('preParsing hooks should run in the order in which they are defined', t =>
2666
2666
 
2667
2667
  sget({
2668
2668
  method: 'POST',
2669
- url: 'http://localhost:' + fastify.server.address().port + '/first',
2669
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first',
2670
2670
  body: { hello: 'world' },
2671
2671
  json: true
2672
2672
  }, (err, response, body) => {
@@ -2716,7 +2716,7 @@ test('preParsing hooks should support encapsulation', t => {
2716
2716
 
2717
2717
  sget({
2718
2718
  method: 'POST',
2719
- url: 'http://localhost:' + fastify.server.address().port + '/first',
2719
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first',
2720
2720
  body: { hello: 'world' },
2721
2721
  json: true
2722
2722
  }, (err, response, body) => {
@@ -2728,7 +2728,7 @@ test('preParsing hooks should support encapsulation', t => {
2728
2728
 
2729
2729
  sget({
2730
2730
  method: 'POST',
2731
- url: 'http://localhost:' + fastify.server.address().port + '/second',
2731
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second',
2732
2732
  body: { hello: 'world' },
2733
2733
  json: true
2734
2734
  }, (err, response, body) => {
@@ -2837,7 +2837,7 @@ test('preParsing hook should support encapsulation / 3', t => {
2837
2837
 
2838
2838
  sget({
2839
2839
  method: 'GET',
2840
- url: 'http://localhost:' + fastify.server.address().port + '/first'
2840
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
2841
2841
  }, (err, response, body) => {
2842
2842
  t.error(err)
2843
2843
  t.equal(response.statusCode, 200)
@@ -2847,7 +2847,7 @@ test('preParsing hook should support encapsulation / 3', t => {
2847
2847
 
2848
2848
  sget({
2849
2849
  method: 'GET',
2850
- url: 'http://localhost:' + fastify.server.address().port + '/second'
2850
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
2851
2851
  }, (err, response, body) => {
2852
2852
  t.error(err)
2853
2853
  t.equal(response.statusCode, 200)
@@ -2899,7 +2899,7 @@ test('preSerialization hook should run before serialization and be able to modif
2899
2899
 
2900
2900
  sget({
2901
2901
  method: 'GET',
2902
- url: 'http://localhost:' + fastify.server.address().port + '/first'
2902
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
2903
2903
  }, (err, response, body) => {
2904
2904
  t.error(err)
2905
2905
  t.equal(response.statusCode, 200)
@@ -2950,7 +2950,7 @@ test('preSerialization hook should be able to throw errors which are validated a
2950
2950
 
2951
2951
  sget({
2952
2952
  method: 'GET',
2953
- url: 'http://localhost:' + fastify.server.address().port + '/first'
2953
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
2954
2954
  }, (err, response, body) => {
2955
2955
  t.error(err)
2956
2956
  t.equal(response.statusCode, 500)
@@ -2984,7 +2984,7 @@ test('preSerialization hook which returned error should still run onError hooks'
2984
2984
 
2985
2985
  sget({
2986
2986
  method: 'GET',
2987
- url: 'http://localhost:' + fastify.server.address().port + '/first'
2987
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
2988
2988
  }, (err, response, body) => {
2989
2989
  t.error(err)
2990
2990
  t.equal(response.statusCode, 500)
@@ -3018,7 +3018,7 @@ test('preSerialization hooks should run in the order in which they are defined',
3018
3018
 
3019
3019
  sget({
3020
3020
  method: 'GET',
3021
- url: 'http://localhost:' + fastify.server.address().port + '/first'
3021
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
3022
3022
  }, (err, response, body) => {
3023
3023
  t.error(err)
3024
3024
  t.equal(response.statusCode, 200)
@@ -3062,7 +3062,7 @@ test('preSerialization hooks should support encapsulation', t => {
3062
3062
 
3063
3063
  sget({
3064
3064
  method: 'GET',
3065
- url: 'http://localhost:' + fastify.server.address().port + '/first'
3065
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/first'
3066
3066
  }, (err, response, body) => {
3067
3067
  t.error(err)
3068
3068
  t.equal(response.statusCode, 200)
@@ -3072,7 +3072,7 @@ test('preSerialization hooks should support encapsulation', t => {
3072
3072
 
3073
3073
  sget({
3074
3074
  method: 'GET',
3075
- url: 'http://localhost:' + fastify.server.address().port + '/second'
3075
+ url: 'http://127.0.0.1:' + fastify.server.address().port + '/second'
3076
3076
  }, (err, response, body) => {
3077
3077
  t.error(err)
3078
3078
  t.equal(response.statusCode, 200)