fastify 5.2.0 → 5.2.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.
Files changed (83) hide show
  1. package/LICENSE +1 -1
  2. package/PROJECT_CHARTER.md +7 -7
  3. package/README.md +65 -67
  4. package/SPONSORS.md +2 -0
  5. package/build/build-validation.js +1 -1
  6. package/docs/Guides/Benchmarking.md +4 -4
  7. package/docs/Guides/Database.md +1 -1
  8. package/docs/Guides/Delay-Accepting-Requests.md +10 -10
  9. package/docs/Guides/Ecosystem.md +5 -1
  10. package/docs/Guides/Fluent-Schema.md +1 -1
  11. package/docs/Guides/Getting-Started.md +9 -5
  12. package/docs/Guides/Index.md +1 -1
  13. package/docs/Guides/Migration-Guide-V4.md +1 -1
  14. package/docs/Guides/Migration-Guide-V5.md +12 -2
  15. package/docs/Guides/Plugins-Guide.md +6 -6
  16. package/docs/Guides/Serverless.md +14 -48
  17. package/docs/Guides/Style-Guide.md +2 -2
  18. package/docs/Guides/Testing.md +2 -2
  19. package/docs/Guides/Write-Plugin.md +2 -3
  20. package/docs/Reference/ContentTypeParser.md +58 -78
  21. package/docs/Reference/Decorators.md +50 -60
  22. package/docs/Reference/Encapsulation.md +28 -33
  23. package/docs/Reference/Errors.md +52 -53
  24. package/docs/Reference/HTTP2.md +7 -7
  25. package/docs/Reference/Hooks.md +31 -30
  26. package/docs/Reference/LTS.md +10 -15
  27. package/docs/Reference/Lifecycle.md +19 -24
  28. package/docs/Reference/Logging.md +59 -56
  29. package/docs/Reference/Middleware.md +19 -19
  30. package/docs/Reference/Plugins.md +55 -71
  31. package/docs/Reference/Principles.md +25 -30
  32. package/docs/Reference/Reply.md +11 -10
  33. package/docs/Reference/Request.md +89 -99
  34. package/docs/Reference/Routes.md +108 -128
  35. package/docs/Reference/Server.md +19 -17
  36. package/docs/Reference/Type-Providers.md +19 -21
  37. package/docs/Reference/TypeScript.md +1 -18
  38. package/docs/Reference/Validation-and-Serialization.md +134 -159
  39. package/docs/Reference/Warnings.md +22 -25
  40. package/fastify.js +1 -1
  41. package/lib/contentTypeParser.js +7 -8
  42. package/lib/error-handler.js +14 -12
  43. package/lib/errors.js +4 -0
  44. package/lib/headRoute.js +4 -2
  45. package/lib/pluginUtils.js +4 -2
  46. package/lib/reply.js +4 -0
  47. package/lib/request.js +13 -9
  48. package/lib/server.js +5 -0
  49. package/lib/validation.js +1 -1
  50. package/lib/warnings.js +9 -0
  51. package/lib/wrapThenable.js +8 -1
  52. package/package.json +28 -17
  53. package/test/build/error-serializer.test.js +2 -1
  54. package/test/bundler/esbuild/package.json +1 -1
  55. package/test/close.test.js +125 -108
  56. package/test/custom-parser-async.test.js +34 -36
  57. package/test/custom-parser.2.test.js +19 -20
  58. package/test/custom-parser.3.test.js +56 -45
  59. package/test/delete.test.js +79 -67
  60. package/test/genReqId.test.js +125 -174
  61. package/test/has-route.test.js +1 -3
  62. package/test/internals/content-type-parser.test.js +1 -1
  63. package/test/internals/errors.test.js +19 -7
  64. package/test/issue-4959.test.js +84 -0
  65. package/test/listen.1.test.js +37 -34
  66. package/test/listen.2.test.js +47 -40
  67. package/test/listen.3.test.js +28 -32
  68. package/test/listen.4.test.js +61 -45
  69. package/test/listen.5.test.js +23 -0
  70. package/test/nullable-validation.test.js +30 -27
  71. package/test/register.test.js +55 -50
  72. package/test/request-error.test.js +114 -94
  73. package/test/route-shorthand.test.js +36 -32
  74. package/test/server.test.js +0 -175
  75. package/test/stream.5.test.js +35 -33
  76. package/test/throw.test.js +87 -91
  77. package/test/toolkit.js +32 -0
  78. package/test/trust-proxy.test.js +23 -23
  79. package/test/types/instance.test-d.ts +1 -0
  80. package/test/upgrade.test.js +32 -30
  81. package/test/web-api.test.js +44 -0
  82. package/types/instance.d.ts +4 -0
  83. package/test/test-reporter.mjs +0 -68
@@ -1,14 +1,13 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
- const test = t.test
3
+ const { test } = require('node:test')
5
4
  const sget = require('simple-get').concat
6
5
  const Fastify = require('../fastify')
7
6
 
8
7
  process.removeAllListeners('warning')
9
8
 
10
- test('contentTypeParser should add a custom async parser', t => {
11
- t.plan(3)
9
+ test('contentTypeParser should add a custom async parser', async t => {
10
+ t.plan(2)
12
11
  const fastify = Fastify()
13
12
 
14
13
  fastify.post('/', (req, reply) => {
@@ -24,43 +23,42 @@ test('contentTypeParser should add a custom async parser', t => {
24
23
  return res
25
24
  })
26
25
 
27
- fastify.listen({ port: 0 }, err => {
28
- t.error(err)
26
+ t.after(() => fastify.close())
27
+ await fastify.listen({ port: 0 })
29
28
 
30
- t.teardown(() => fastify.close())
29
+ await t.test('in POST', (t, done) => {
30
+ t.plan(3)
31
31
 
32
- t.test('in POST', t => {
33
- t.plan(3)
34
-
35
- sget({
36
- method: 'POST',
37
- url: 'http://localhost:' + fastify.server.address().port,
38
- body: '{"hello":"world"}',
39
- headers: {
40
- 'Content-Type': 'application/jsoff'
41
- }
42
- }, (err, response, body) => {
43
- t.error(err)
44
- t.equal(response.statusCode, 200)
45
- t.same(body.toString(), JSON.stringify({ hello: 'world' }))
46
- })
32
+ sget({
33
+ method: 'POST',
34
+ url: 'http://localhost:' + fastify.server.address().port,
35
+ body: '{"hello":"world"}',
36
+ headers: {
37
+ 'Content-Type': 'application/jsoff'
38
+ }
39
+ }, (err, response, body) => {
40
+ t.assert.ifError(err)
41
+ t.assert.strictEqual(response.statusCode, 200)
42
+ t.assert.deepStrictEqual(body.toString(), JSON.stringify({ hello: 'world' }))
43
+ done()
47
44
  })
45
+ })
48
46
 
49
- t.test('in OPTIONS', t => {
50
- t.plan(3)
47
+ await t.test('in OPTIONS', (t, done) => {
48
+ t.plan(3)
51
49
 
52
- sget({
53
- method: 'OPTIONS',
54
- url: 'http://localhost:' + fastify.server.address().port,
55
- body: '{"hello":"world"}',
56
- headers: {
57
- 'Content-Type': 'application/jsoff'
58
- }
59
- }, (err, response, body) => {
60
- t.error(err)
61
- t.equal(response.statusCode, 200)
62
- t.same(body.toString(), JSON.stringify({ hello: 'world' }))
63
- })
50
+ sget({
51
+ method: 'OPTIONS',
52
+ url: 'http://localhost:' + fastify.server.address().port,
53
+ body: '{"hello":"world"}',
54
+ headers: {
55
+ 'Content-Type': 'application/jsoff'
56
+ }
57
+ }, (err, response, body) => {
58
+ t.assert.ifError(err)
59
+ t.assert.strictEqual(response.statusCode, 200)
60
+ t.assert.deepStrictEqual(body.toString(), JSON.stringify({ hello: 'world' }))
61
+ done()
64
62
  })
65
63
  })
66
64
  })
@@ -1,9 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
- const test = t.test
3
+ const { test } = require('node:test')
5
4
  const sget = require('simple-get').concat
6
- const Fastify = require('../fastify')
5
+ const Fastify = require('..')
7
6
  const { getServerUrl } = require('./helper')
8
7
 
9
8
  process.removeAllListeners('warning')
@@ -14,17 +13,17 @@ test('Wrong parseAs parameter', t => {
14
13
 
15
14
  try {
16
15
  fastify.addContentTypeParser('application/json', { parseAs: 'fireworks' }, () => {})
17
- t.fail('should throw')
16
+ t.assert.fail('should throw')
18
17
  } catch (err) {
19
- t.equal(err.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
20
- t.equal(err.message, "The body parser can only parse your data as 'string' or 'buffer', you asked 'fireworks' which is not supported.")
18
+ t.assert.strictEqual(err.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
19
+ t.assert.strictEqual(err.message, "The body parser can only parse your data as 'string' or 'buffer', you asked 'fireworks' which is not supported.")
21
20
  }
22
21
  })
23
22
 
24
- test('Should allow defining the bodyLimit per parser', t => {
23
+ test('Should allow defining the bodyLimit per parser', (t, done) => {
25
24
  t.plan(3)
26
25
  const fastify = Fastify()
27
- t.teardown(() => fastify.close())
26
+ t.after(() => fastify.close())
28
27
 
29
28
  fastify.post('/', (req, reply) => {
30
29
  reply.send(req.body)
@@ -34,13 +33,13 @@ test('Should allow defining the bodyLimit per parser', t => {
34
33
  'x/foo',
35
34
  { parseAs: 'string', bodyLimit: 5 },
36
35
  function (req, body, done) {
37
- t.fail('should not be invoked')
36
+ t.assert.fail('should not be invoked')
38
37
  done()
39
38
  }
40
39
  )
41
40
 
42
41
  fastify.listen({ port: 0 }, err => {
43
- t.error(err)
42
+ t.assert.ifError(err)
44
43
 
45
44
  sget({
46
45
  method: 'POST',
@@ -50,22 +49,22 @@ test('Should allow defining the bodyLimit per parser', t => {
50
49
  'Content-Type': 'x/foo'
51
50
  }
52
51
  }, (err, response, body) => {
53
- t.error(err)
54
- t.strictSame(JSON.parse(body.toString()), {
52
+ t.assert.ifError(err)
53
+ t.assert.deepStrictEqual(JSON.parse(body.toString()), {
55
54
  statusCode: 413,
56
55
  code: 'FST_ERR_CTP_BODY_TOO_LARGE',
57
56
  error: 'Payload Too Large',
58
57
  message: 'Request body is too large'
59
58
  })
60
- fastify.close()
59
+ done()
61
60
  })
62
61
  })
63
62
  })
64
63
 
65
- test('route bodyLimit should take precedence over a custom parser bodyLimit', t => {
64
+ test('route bodyLimit should take precedence over a custom parser bodyLimit', (t, done) => {
66
65
  t.plan(3)
67
66
  const fastify = Fastify()
68
- t.teardown(() => fastify.close())
67
+ t.after(() => fastify.close())
69
68
 
70
69
  fastify.post('/', { bodyLimit: 5 }, (request, reply) => {
71
70
  reply.send(request.body)
@@ -75,13 +74,13 @@ test('route bodyLimit should take precedence over a custom parser bodyLimit', t
75
74
  'x/foo',
76
75
  { parseAs: 'string', bodyLimit: 100 },
77
76
  function (req, body, done) {
78
- t.fail('should not be invoked')
77
+ t.assert.fail('should not be invoked')
79
78
  done()
80
79
  }
81
80
  )
82
81
 
83
82
  fastify.listen({ port: 0 }, err => {
84
- t.error(err)
83
+ t.assert.ifError(err)
85
84
 
86
85
  sget({
87
86
  method: 'POST',
@@ -89,14 +88,14 @@ test('route bodyLimit should take precedence over a custom parser bodyLimit', t
89
88
  body: '1234567890',
90
89
  headers: { 'Content-Type': 'x/foo' }
91
90
  }, (err, response, body) => {
92
- t.error(err)
93
- t.strictSame(JSON.parse(body.toString()), {
91
+ t.assert.ifError(err)
92
+ t.assert.deepStrictEqual(JSON.parse(body.toString()), {
94
93
  statusCode: 413,
95
94
  code: 'FST_ERR_CTP_BODY_TOO_LARGE',
96
95
  error: 'Payload Too Large',
97
96
  message: 'Request body is too large'
98
97
  })
99
- fastify.close()
98
+ done()
100
99
  })
101
100
  })
102
101
  })
@@ -1,18 +1,17 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
- const test = t.test
3
+ const { test } = require('node:test')
5
4
  const sget = require('simple-get').concat
6
- const Fastify = require('../fastify')
5
+ const Fastify = require('..')
7
6
  const jsonParser = require('fast-json-body')
8
7
  const { getServerUrl } = require('./helper')
9
8
 
10
9
  process.removeAllListeners('warning')
11
10
 
12
- test('should be able to use default parser for extra content type', t => {
11
+ test('should be able to use default parser for extra content type', (t, done) => {
13
12
  t.plan(4)
14
13
  const fastify = Fastify()
15
- t.teardown(() => fastify.close())
14
+ t.after(() => fastify.close())
16
15
 
17
16
  fastify.post('/', (request, reply) => {
18
17
  reply.send(request.body)
@@ -21,7 +20,7 @@ test('should be able to use default parser for extra content type', t => {
21
20
  fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
22
21
 
23
22
  fastify.listen({ port: 0 }, err => {
24
- t.error(err)
23
+ t.assert.ifError(err)
25
24
 
26
25
  sget({
27
26
  method: 'POST',
@@ -31,18 +30,17 @@ test('should be able to use default parser for extra content type', t => {
31
30
  'Content-Type': 'text/json'
32
31
  }
33
32
  }, (err, response, body) => {
34
- t.error(err)
35
- t.equal(response.statusCode, 200)
36
- t.strictSame(JSON.parse(body.toString()), { hello: 'world' })
37
- fastify.close()
33
+ t.assert.ifError(err)
34
+ t.assert.strictEqual(response.statusCode, 200)
35
+ t.assert.deepStrictEqual(JSON.parse(body.toString()), { hello: 'world' })
36
+ done()
38
37
  })
39
38
  })
40
39
  })
41
40
 
42
- test('contentTypeParser should add a custom parser with RegExp value', t => {
43
- t.plan(3)
44
-
41
+ test('contentTypeParser should add a custom parser with RegExp value', async (t) => {
45
42
  const fastify = Fastify()
43
+ t.after(() => fastify.close())
46
44
 
47
45
  fastify.post('/', (req, reply) => {
48
46
  reply.send(req.body)
@@ -58,13 +56,12 @@ test('contentTypeParser should add a custom parser with RegExp value', t => {
58
56
  })
59
57
  })
60
58
 
61
- fastify.listen({ port: 0 }, err => {
62
- t.error(err)
63
-
64
- t.teardown(() => fastify.close())
59
+ fastify.listen({ port: 0 }, async err => {
60
+ t.assert.ifError(err)
65
61
 
66
- t.test('in POST', t => {
62
+ await t.test('in POST', (t, done) => {
67
63
  t.plan(3)
64
+ t.after(() => fastify.close())
68
65
 
69
66
  sget({
70
67
  method: 'POST',
@@ -74,14 +71,16 @@ test('contentTypeParser should add a custom parser with RegExp value', t => {
74
71
  'Content-Type': 'application/vnd.test+json'
75
72
  }
76
73
  }, (err, response, body) => {
77
- t.error(err)
78
- t.equal(response.statusCode, 200)
79
- t.same(body.toString(), JSON.stringify({ hello: 'world' }))
74
+ t.assert.ifError(err)
75
+ t.assert.strictEqual(response.statusCode, 200)
76
+ t.assert.deepStrictEqual(body.toString(), JSON.stringify({ hello: 'world' }))
77
+ done()
80
78
  })
81
79
  })
82
80
 
83
- t.test('in OPTIONS', t => {
81
+ await t.test('in OPTIONS', (t, done) => {
84
82
  t.plan(3)
83
+ t.after(() => fastify.close())
85
84
 
86
85
  sget({
87
86
  method: 'OPTIONS',
@@ -91,9 +90,10 @@ test('contentTypeParser should add a custom parser with RegExp value', t => {
91
90
  'Content-Type': 'weird/content-type+json'
92
91
  }
93
92
  }, (err, response, body) => {
94
- t.error(err)
95
- t.equal(response.statusCode, 200)
96
- t.same(body.toString(), JSON.stringify({ hello: 'world' }))
93
+ t.assert.ifError(err)
94
+ t.assert.strictEqual(response.statusCode, 200)
95
+ t.assert.deepStrictEqual(body.toString(), JSON.stringify({ hello: 'world' }))
96
+ done()
97
97
  })
98
98
  })
99
99
  })
@@ -102,7 +102,7 @@ test('contentTypeParser should add a custom parser with RegExp value', t => {
102
102
  test('contentTypeParser should add multiple custom parsers with RegExp values', async t => {
103
103
  t.plan(6)
104
104
  const fastify = Fastify()
105
- t.teardown(fastify.close.bind(fastify))
105
+ t.after(() => fastify.close())
106
106
 
107
107
  fastify.post('/', (req, reply) => {
108
108
  reply.send(req.body)
@@ -137,8 +137,8 @@ test('contentTypeParser should add multiple custom parsers with RegExp values',
137
137
  'Content-Type': 'application/vnd.hello+json'
138
138
  }
139
139
  })
140
- t.equal(response.statusCode, 200)
141
- t.same(response.payload.toString(), '{"hello":"world"}')
140
+ t.assert.strictEqual(response.statusCode, 200)
141
+ t.assert.deepStrictEqual(response.payload.toString(), '{"hello":"world"}')
142
142
  }
143
143
 
144
144
  {
@@ -150,8 +150,8 @@ test('contentTypeParser should add multiple custom parsers with RegExp values',
150
150
  'Content-Type': 'application/test+xml'
151
151
  }
152
152
  })
153
- t.equal(response.statusCode, 200)
154
- t.same(response.payload.toString(), 'xml')
153
+ t.assert.strictEqual(response.statusCode, 200)
154
+ t.assert.deepStrictEqual(response.payload.toString(), 'xml')
155
155
  }
156
156
 
157
157
  await fastify.inject({
@@ -162,17 +162,17 @@ test('contentTypeParser should add multiple custom parsers with RegExp values',
162
162
  'Content-Type': 'application/+myExtension'
163
163
  }
164
164
  }).then((response) => {
165
- t.equal(response.statusCode, 200)
166
- t.same(response.payload.toString(), 'abcdefgmyExtension')
165
+ t.assert.strictEqual(response.statusCode, 200)
166
+ t.assert.deepStrictEqual(response.payload.toString(), 'abcdefgmyExtension')
167
167
  }).catch((err) => {
168
- t.error(err)
168
+ t.assert.ifError(err)
169
169
  })
170
170
  })
171
171
 
172
- test('catch all content type parser should not interfere with content type parser', t => {
172
+ test('catch all content type parser should not interfere with content type parser', (t, done) => {
173
173
  t.plan(10)
174
174
  const fastify = Fastify()
175
- t.teardown(fastify.close.bind(fastify))
175
+ t.after(() => fastify.close())
176
176
 
177
177
  fastify.post('/', (req, reply) => {
178
178
  reply.send(req.body)
@@ -201,7 +201,15 @@ test('catch all content type parser should not interfere with content type parse
201
201
  })
202
202
 
203
203
  fastify.listen({ port: 0 }, err => {
204
- t.error(err)
204
+ t.assert.ifError(err)
205
+
206
+ let pending = 3
207
+
208
+ function completed () {
209
+ if (--pending === 0) {
210
+ done()
211
+ }
212
+ }
205
213
 
206
214
  sget({
207
215
  method: 'POST',
@@ -211,9 +219,10 @@ test('catch all content type parser should not interfere with content type parse
211
219
  'Content-Type': 'application/json'
212
220
  }
213
221
  }, (err, response, body) => {
214
- t.error(err)
215
- t.equal(response.statusCode, 200)
216
- t.same(body.toString(), JSON.stringify({ myKey: 'myValue' }))
222
+ t.assert.ifError(err)
223
+ t.assert.strictEqual(response.statusCode, 200)
224
+ t.assert.deepStrictEqual(body.toString(), JSON.stringify({ myKey: 'myValue' }))
225
+ completed()
217
226
  })
218
227
 
219
228
  sget({
@@ -224,9 +233,10 @@ test('catch all content type parser should not interfere with content type parse
224
233
  'Content-Type': 'very-weird-content-type'
225
234
  }
226
235
  }, (err, response, body) => {
227
- t.error(err)
228
- t.equal(response.statusCode, 200)
229
- t.same(body.toString(), 'body')
236
+ t.assert.ifError(err)
237
+ t.assert.strictEqual(response.statusCode, 200)
238
+ t.assert.deepStrictEqual(body.toString(), 'body')
239
+ completed()
230
240
  })
231
241
 
232
242
  sget({
@@ -237,9 +247,10 @@ test('catch all content type parser should not interfere with content type parse
237
247
  'Content-Type': 'text/html'
238
248
  }
239
249
  }, (err, response, body) => {
240
- t.error(err)
241
- t.equal(response.statusCode, 200)
242
- t.same(body.toString(), 'my texthtml')
250
+ t.assert.ifError(err)
251
+ t.assert.strictEqual(response.statusCode, 200)
252
+ t.assert.deepStrictEqual(body.toString(), 'my texthtml')
253
+ completed()
243
254
  })
244
255
  })
245
256
  })