fastify 3.26.0 → 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.
Files changed (129) hide show
  1. package/README.md +5 -4
  2. package/build/build-error-serializer.js +27 -0
  3. package/build/build-validation.js +49 -35
  4. package/docs/Guides/Ecosystem.md +2 -1
  5. package/docs/Guides/Prototype-Poisoning.md +3 -3
  6. package/docs/Migration-Guide-V4.md +12 -0
  7. package/docs/Reference/ContentTypeParser.md +8 -1
  8. package/docs/Reference/Errors.md +51 -6
  9. package/docs/Reference/Hooks.md +4 -7
  10. package/docs/Reference/LTS.md +5 -4
  11. package/docs/Reference/Reply.md +23 -22
  12. package/docs/Reference/Request.md +1 -3
  13. package/docs/Reference/Routes.md +17 -10
  14. package/docs/Reference/Server.md +98 -63
  15. package/docs/Reference/TypeScript.md +11 -13
  16. package/docs/Reference/Validation-and-Serialization.md +32 -54
  17. package/docs/Type-Providers.md +257 -0
  18. package/examples/hooks.js +1 -1
  19. package/examples/simple-stream.js +18 -0
  20. package/fastify.d.ts +36 -22
  21. package/fastify.js +72 -53
  22. package/lib/configValidator.js +902 -1023
  23. package/lib/contentTypeParser.js +6 -16
  24. package/lib/context.js +36 -10
  25. package/lib/decorate.js +5 -3
  26. package/lib/error-handler.js +158 -0
  27. package/lib/error-serializer.js +257 -0
  28. package/lib/errors.js +49 -10
  29. package/lib/fourOhFour.js +31 -20
  30. package/lib/handleRequest.js +10 -13
  31. package/lib/hooks.js +14 -9
  32. package/lib/noop-set.js +10 -0
  33. package/lib/pluginOverride.js +0 -3
  34. package/lib/pluginUtils.js +3 -2
  35. package/lib/reply.js +44 -163
  36. package/lib/request.js +13 -10
  37. package/lib/route.js +158 -139
  38. package/lib/schema-controller.js +3 -3
  39. package/lib/schemas.js +27 -1
  40. package/lib/server.js +219 -116
  41. package/lib/symbols.js +6 -4
  42. package/lib/validation.js +2 -1
  43. package/lib/warnings.js +2 -12
  44. package/lib/wrapThenable.js +4 -11
  45. package/package.json +40 -45
  46. package/test/404s.test.js +265 -108
  47. package/test/500s.test.js +2 -2
  48. package/test/async-await.test.js +15 -71
  49. package/test/close.test.js +39 -1
  50. package/test/content-parser.test.js +32 -0
  51. package/test/context-config.test.js +56 -4
  52. package/test/custom-http-server.test.js +14 -7
  53. package/test/custom-parser-async.test.js +0 -65
  54. package/test/custom-parser.test.js +54 -121
  55. package/test/decorator.test.js +1 -3
  56. package/test/delete.test.js +5 -5
  57. package/test/encapsulated-error-handler.test.js +50 -0
  58. package/test/esm/index.test.js +0 -14
  59. package/test/fastify-instance.test.js +4 -4
  60. package/test/fluent-schema.test.js +4 -4
  61. package/test/get.test.js +3 -3
  62. package/test/helper.js +18 -3
  63. package/test/hooks-async.test.js +14 -47
  64. package/test/hooks.on-ready.test.js +9 -4
  65. package/test/hooks.test.js +58 -99
  66. package/test/http2/closing.test.js +5 -11
  67. package/test/http2/unknown-http-method.test.js +3 -9
  68. package/test/https/custom-https-server.test.js +12 -6
  69. package/test/inject.test.js +1 -1
  70. package/test/input-validation.js +2 -2
  71. package/test/internals/all.test.js +2 -2
  72. package/test/internals/contentTypeParser.test.js +4 -4
  73. package/test/internals/handleRequest.test.js +9 -46
  74. package/test/internals/initialConfig.test.js +33 -12
  75. package/test/internals/logger.test.js +1 -1
  76. package/test/internals/reply.test.js +245 -3
  77. package/test/internals/request.test.js +13 -7
  78. package/test/internals/server.test.js +88 -0
  79. package/test/listen.test.js +84 -1
  80. package/test/logger.test.js +98 -58
  81. package/test/maxRequestsPerSocket.test.js +8 -6
  82. package/test/middleware.test.js +2 -25
  83. package/test/noop-set.test.js +19 -0
  84. package/test/nullable-validation.test.js +51 -14
  85. package/test/plugin.test.js +31 -5
  86. package/test/pretty-print.test.js +22 -10
  87. package/test/reply-error.test.js +123 -12
  88. package/test/request-error.test.js +2 -5
  89. package/test/route-hooks.test.js +17 -17
  90. package/test/route-prefix.test.js +2 -1
  91. package/test/route.test.js +216 -20
  92. package/test/router-options.test.js +1 -1
  93. package/test/schema-examples.test.js +11 -5
  94. package/test/schema-feature.test.js +24 -19
  95. package/test/schema-serialization.test.js +50 -9
  96. package/test/schema-special-usage.test.js +14 -81
  97. package/test/schema-validation.test.js +9 -9
  98. package/test/skip-reply-send.test.js +8 -8
  99. package/test/stream.test.js +23 -12
  100. package/test/throw.test.js +8 -5
  101. package/test/trust-proxy.test.js +1 -1
  102. package/test/type-provider.test.js +20 -0
  103. package/test/types/fastify.test-d.ts +12 -18
  104. package/test/types/hooks.test-d.ts +7 -3
  105. package/test/types/import.js +2 -0
  106. package/test/types/import.ts +1 -0
  107. package/test/types/instance.test-d.ts +61 -15
  108. package/test/types/logger.test-d.ts +44 -15
  109. package/test/types/route.test-d.ts +8 -2
  110. package/test/types/schema.test-d.ts +2 -39
  111. package/test/types/type-provider.test-d.ts +417 -0
  112. package/test/validation-error-handling.test.js +9 -9
  113. package/test/versioned-routes.test.js +29 -17
  114. package/test/wrapThenable.test.js +7 -6
  115. package/types/.eslintrc.json +1 -1
  116. package/types/content-type-parser.d.ts +17 -8
  117. package/types/hooks.d.ts +107 -60
  118. package/types/instance.d.ts +137 -105
  119. package/types/logger.d.ts +18 -104
  120. package/types/plugin.d.ts +10 -4
  121. package/types/register.d.ts +1 -1
  122. package/types/reply.d.ts +16 -11
  123. package/types/request.d.ts +10 -5
  124. package/types/route.d.ts +42 -31
  125. package/types/schema.d.ts +15 -1
  126. package/types/type-provider.d.ts +99 -0
  127. package/types/utils.d.ts +1 -1
  128. package/lib/schema-compilers.js +0 -12
  129. package/test/emit-warning.test.js +0 -166
@@ -0,0 +1,417 @@
1
+ import fastify, { FastifyTypeProvider } from '../../fastify'
2
+ import { expectAssignable, expectError, expectType } from 'tsd'
3
+ import { IncomingHttpHeaders } from 'http'
4
+ import { Type, TSchema, Static } from '@sinclair/typebox'
5
+ import { FromSchema, JSONSchema } from 'json-schema-to-ts'
6
+
7
+ const server = fastify()
8
+
9
+ // -------------------------------------------------------------------
10
+ // Remapping
11
+ // -------------------------------------------------------------------
12
+
13
+ interface NumberProvider extends FastifyTypeProvider { output: number } // remap all schemas to numbers
14
+
15
+ expectAssignable(server.withTypeProvider<NumberProvider>().get(
16
+ '/',
17
+ {
18
+ schema: {
19
+ body: { type: 'string' },
20
+ querystring: { type: 'string' },
21
+ headers: { type: 'string' },
22
+ params: { type: 'string' }
23
+ }
24
+ },
25
+ (req) => {
26
+ expectType<number & IncomingHttpHeaders>(req.headers)
27
+ expectType<number>(req.body)
28
+ expectType<number>(req.query)
29
+ expectType<number>(req.params)
30
+ }
31
+ ))
32
+
33
+ // -------------------------------------------------------------------
34
+ // Override
35
+ // -------------------------------------------------------------------
36
+
37
+ interface OverriddenProvider extends FastifyTypeProvider { output: 'inferenced' }
38
+
39
+ expectAssignable(server.withTypeProvider<OverriddenProvider>().get<{ Body: 'override' }>(
40
+ '/',
41
+ {
42
+ schema: {
43
+ body: Type.Object({
44
+ x: Type.Number(),
45
+ y: Type.Number(),
46
+ z: Type.Number()
47
+ })
48
+ }
49
+ },
50
+ (req) => {
51
+ expectType<'override'>(req.body)
52
+ }
53
+ ))
54
+
55
+ // -------------------------------------------------------------------
56
+ // TypeBox
57
+ // -------------------------------------------------------------------
58
+
59
+ interface TypeBoxProvider extends FastifyTypeProvider { output: this['input'] extends TSchema ? Static<this['input']> : never }
60
+
61
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
62
+ '/',
63
+ {
64
+ schema: {
65
+ body: Type.Object({
66
+ x: Type.Number(),
67
+ y: Type.Number(),
68
+ z: Type.Number()
69
+ })
70
+ }
71
+ },
72
+ (req) => {
73
+ expectType<number>(req.body.x)
74
+ expectType<number>(req.body.y)
75
+ expectType<number>(req.body.z)
76
+ }
77
+ ))
78
+
79
+ // -------------------------------------------------------------------
80
+ // JsonSchemaToTs
81
+ // -------------------------------------------------------------------
82
+
83
+ interface JsonSchemaToTsProvider extends FastifyTypeProvider { output: this['input'] extends JSONSchema ? FromSchema<this['input']> : never }
84
+
85
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
86
+ '/',
87
+ {
88
+ schema: {
89
+ body: {
90
+ type: 'object',
91
+ properties: {
92
+ x: { type: 'number' },
93
+ y: { type: 'string' },
94
+ z: { type: 'boolean' }
95
+ }
96
+ } as const
97
+ }
98
+ },
99
+ (req) => {
100
+ expectType<number | undefined>(req.body.x)
101
+ expectType<string | undefined>(req.body.y)
102
+ expectType<boolean | undefined>(req.body.z)
103
+ }
104
+ ))
105
+
106
+ // -------------------------------------------------------------------
107
+ // Instance Type Remappable
108
+ // -------------------------------------------------------------------
109
+
110
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().withTypeProvider<JsonSchemaToTsProvider>().get(
111
+ '/',
112
+ {
113
+ schema: {
114
+ body: {
115
+ type: 'object',
116
+ properties: {
117
+ x: { type: 'number' },
118
+ y: { type: 'string' },
119
+ z: { type: 'boolean' }
120
+ }
121
+ } as const
122
+ }
123
+ },
124
+ (req) => {
125
+ expectType<number | undefined>(req.body.x)
126
+ expectType<string | undefined>(req.body.y)
127
+ expectType<boolean | undefined>(req.body.z)
128
+ }
129
+ ))
130
+
131
+ // -------------------------------------------------------------------
132
+ // Request Hooks
133
+ // -------------------------------------------------------------------
134
+
135
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
136
+ '/',
137
+ {
138
+ schema: {
139
+ body: Type.Object({
140
+ x: Type.Number(),
141
+ y: Type.String(),
142
+ z: Type.Boolean()
143
+ })
144
+ },
145
+ preHandler: req => {
146
+ expectType<number>(req.body.x)
147
+ expectType<string>(req.body.y)
148
+ expectType<boolean>(req.body.z)
149
+ },
150
+ preParsing: req => {
151
+ expectType<number>(req.body.x)
152
+ expectType<string>(req.body.y)
153
+ expectType<boolean>(req.body.z)
154
+ },
155
+ preSerialization: req => {
156
+ expectType<number>(req.body.x)
157
+ expectType<string>(req.body.y)
158
+ expectType<boolean>(req.body.z)
159
+ },
160
+ preValidation: req => {
161
+ expectType<number>(req.body.x)
162
+ expectType<string>(req.body.y)
163
+ expectType<boolean>(req.body.z)
164
+ },
165
+ onError: req => {
166
+ expectType<number>(req.body.x)
167
+ expectType<string>(req.body.y)
168
+ expectType<boolean>(req.body.z)
169
+ },
170
+ onRequest: req => {
171
+ expectType<number>(req.body.x)
172
+ expectType<string>(req.body.y)
173
+ expectType<boolean>(req.body.z)
174
+ },
175
+ onResponse: req => {
176
+ expectType<number>(req.body.x)
177
+ expectType<string>(req.body.y)
178
+ expectType<boolean>(req.body.z)
179
+ },
180
+ onTimeout: req => {
181
+ expectType<number>(req.body.x)
182
+ expectType<string>(req.body.y)
183
+ expectType<boolean>(req.body.z)
184
+ },
185
+ onSend: req => {
186
+ expectType<number>(req.body.x)
187
+ expectType<string>(req.body.y)
188
+ expectType<boolean>(req.body.z)
189
+ }
190
+ },
191
+ req => {
192
+ expectType<number>(req.body.x)
193
+ expectType<string>(req.body.y)
194
+ expectType<boolean>(req.body.z)
195
+ }
196
+ ))
197
+
198
+ // -------------------------------------------------------------------
199
+ // TypeBox Reply Type
200
+ // -------------------------------------------------------------------
201
+
202
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
203
+ '/',
204
+ {
205
+ schema: {
206
+ response: {
207
+ 200: Type.String(),
208
+ 400: Type.Number(),
209
+ 500: Type.Object({
210
+ error: Type.String()
211
+ })
212
+ }
213
+ }
214
+ },
215
+ async (_, res) => {
216
+ res.send('hello')
217
+ res.send(42)
218
+ res.send({ error: 'error' })
219
+ }
220
+ ))
221
+
222
+ // -------------------------------------------------------------------
223
+ // TypeBox Reply Type: Non Assignable
224
+ // -------------------------------------------------------------------
225
+
226
+ expectError(server.withTypeProvider<TypeBoxProvider>().get(
227
+ '/',
228
+ {
229
+ schema: {
230
+ response: {
231
+ 200: Type.String(),
232
+ 400: Type.Number(),
233
+ 500: Type.Object({
234
+ error: Type.String()
235
+ })
236
+ }
237
+ }
238
+ },
239
+ async (_, res) => {
240
+ res.send(false)
241
+ }
242
+ ))
243
+
244
+ // -------------------------------------------------------------------
245
+ // TypeBox Reply Return Type
246
+ // -------------------------------------------------------------------
247
+
248
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
249
+ '/',
250
+ {
251
+ schema: {
252
+ response: {
253
+ 200: Type.String(),
254
+ 400: Type.Number(),
255
+ 500: Type.Object({
256
+ error: Type.String()
257
+ })
258
+ }
259
+ }
260
+ },
261
+ async (_, res) => {
262
+ const option = 1 as 1 | 2 | 3
263
+ switch (option) {
264
+ case 1: return 'hello'
265
+ case 2: return 42
266
+ case 3: return { error: 'error' }
267
+ }
268
+ }
269
+ ))
270
+
271
+ // -------------------------------------------------------------------
272
+ // TypeBox Reply Return Type: Non Assignable
273
+ // -------------------------------------------------------------------
274
+
275
+ expectError(server.withTypeProvider<TypeBoxProvider>().get(
276
+ '/',
277
+ {
278
+ schema: {
279
+ response: {
280
+ 200: Type.String(),
281
+ 400: Type.Number(),
282
+ 500: Type.Object({
283
+ error: Type.String()
284
+ })
285
+ }
286
+ }
287
+ },
288
+ async (_, res) => {
289
+ return false
290
+ }
291
+ ))
292
+
293
+ // -------------------------------------------------------------------
294
+ // JsonSchemaToTs Reply Type
295
+ // -------------------------------------------------------------------
296
+
297
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
298
+ '/',
299
+ {
300
+ schema: {
301
+ response: {
302
+ 200: { type: 'string' },
303
+ 400: { type: 'number' },
304
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
305
+ } as const
306
+ }
307
+ },
308
+ (_, res) => {
309
+ res.send('hello')
310
+ res.send(42)
311
+ res.send({ error: 'error' })
312
+ }
313
+ ))
314
+
315
+ // -------------------------------------------------------------------
316
+ // JsonSchemaToTs Reply Type: Non Assignable
317
+ // -------------------------------------------------------------------
318
+
319
+ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get(
320
+ '/',
321
+ {
322
+ schema: {
323
+ response: {
324
+ 200: { type: 'string' },
325
+ 400: { type: 'number' },
326
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
327
+ } as const
328
+ }
329
+ },
330
+ async (_, res) => {
331
+ res.send(false)
332
+ }
333
+ ))
334
+
335
+ // -------------------------------------------------------------------
336
+ // JsonSchemaToTs Reply Type Return
337
+ // -------------------------------------------------------------------
338
+
339
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
340
+ '/',
341
+ {
342
+ schema: {
343
+ response: {
344
+ 200: { type: 'string' },
345
+ 400: { type: 'number' },
346
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
347
+ } as const
348
+ }
349
+ },
350
+ async (_, res) => {
351
+ const option = 1 as 1 | 2 | 3
352
+ switch (option) {
353
+ case 1: return 'hello'
354
+ case 2: return 42
355
+ case 3: return { error: 'error' }
356
+ }
357
+ }
358
+ ))
359
+ // -------------------------------------------------------------------
360
+ // JsonSchemaToTs Reply Type Return: Non Assignable
361
+ // -------------------------------------------------------------------
362
+
363
+ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get(
364
+ '/',
365
+ {
366
+ schema: {
367
+ response: {
368
+ 200: { type: 'string' },
369
+ 400: { type: 'number' },
370
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
371
+ } as const
372
+ }
373
+ },
374
+ async (_, res) => {
375
+ return false
376
+ }
377
+ ))
378
+
379
+ // -------------------------------------------------------------------
380
+ // Reply Type Override
381
+ // -------------------------------------------------------------------
382
+
383
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
384
+ '/',
385
+ {
386
+ schema: {
387
+ response: {
388
+ 200: { type: 'string' },
389
+ 400: { type: 'number' },
390
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
391
+ } as const
392
+ }
393
+ },
394
+ async (_, res) => {
395
+ res.send(true)
396
+ }
397
+ ))
398
+
399
+ // -------------------------------------------------------------------
400
+ // Reply Type Return Override
401
+ // -------------------------------------------------------------------
402
+
403
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
404
+ '/',
405
+ {
406
+ schema: {
407
+ response: {
408
+ 200: { type: 'string' },
409
+ 400: { type: 'number' },
410
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
411
+ } as const
412
+ }
413
+ },
414
+ async (_, res) => {
415
+ return true
416
+ }
417
+ ))
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { test } = require('tap')
4
- const Joi = require('@hapi/joi')
4
+ const Joi = require('joi')
5
5
  const Fastify = require('..')
6
6
 
7
7
  const schema = {
@@ -58,7 +58,7 @@ test('should fail immediately with invalid payload', t => {
58
58
  t.same(res.json(), {
59
59
  statusCode: 400,
60
60
  error: 'Bad Request',
61
- message: "body should have required property 'name'"
61
+ message: "body must have required property 'name'"
62
62
  })
63
63
  t.equal(res.statusCode, 400)
64
64
  })
@@ -140,7 +140,7 @@ test('error inside custom error handler should have validationContext if specifi
140
140
  return function (data) {
141
141
  const error = new Error('this failed')
142
142
  error.validationContext = 'customContext'
143
- return { error: error }
143
+ return { error }
144
144
  }
145
145
  }
146
146
  }, function (req, reply) {
@@ -183,10 +183,10 @@ test('should be able to attach validation to request', t => {
183
183
 
184
184
  t.same(res.json(), [{
185
185
  keyword: 'required',
186
- dataPath: '',
186
+ instancePath: '',
187
187
  schemaPath: '#/required',
188
188
  params: { missingProperty: 'name' },
189
- message: 'should have required property \'name\''
189
+ message: 'must have required property \'name\''
190
190
  }])
191
191
  t.equal(res.statusCode, 400)
192
192
  })
@@ -213,7 +213,7 @@ test('should respect when attachValidation is explicitly set to false', t => {
213
213
  t.same(JSON.parse(res.payload), {
214
214
  statusCode: 400,
215
215
  error: 'Bad Request',
216
- message: "body should have required property 'name'"
216
+ message: "body must have required property 'name'"
217
217
  })
218
218
  t.equal(res.statusCode, 400)
219
219
  })
@@ -243,7 +243,7 @@ test('Attached validation error should take precedence over setErrorHandler', t
243
243
  url: '/'
244
244
  }, (err, res) => {
245
245
  t.error(err)
246
- t.same(res.payload, "Attached: Error: body should have required property 'name'")
246
+ t.same(res.payload, "Attached: Error: body must have required property 'name'")
247
247
  t.equal(res.statusCode, 400)
248
248
  })
249
249
  })
@@ -336,7 +336,7 @@ test('should return a defined output message parsing AJV errors', t => {
336
336
  url: '/'
337
337
  }, (err, res) => {
338
338
  t.error(err)
339
- t.equal(res.payload, '{"statusCode":400,"error":"Bad Request","message":"body should have required property \'name\'"}')
339
+ t.equal(res.payload, '{"statusCode":400,"error":"Bad Request","message":"body must have required property \'name\'"}')
340
340
  })
341
341
  })
342
342
 
@@ -467,7 +467,7 @@ test('should call custom error formatter', t => {
467
467
  const fastify = Fastify({
468
468
  schemaErrorFormatter: (errors, dataVar) => {
469
469
  t.equal(errors.length, 1)
470
- t.equal(errors[0].message, "should have required property 'name'")
470
+ t.equal(errors[0].message, "must have required property 'name'")
471
471
  t.equal(dataVar, 'body')
472
472
  return new Error('my error')
473
473
  }
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
- const test = t.test
3
+ const { test, before } = require('tap')
4
+ const helper = require('./helper')
5
5
  const Fastify = require('..')
6
6
  const sget = require('simple-get').concat
7
7
  const http = require('http')
@@ -9,6 +9,13 @@ const split = require('split2')
9
9
  const append = require('vary').append
10
10
  const proxyquire = require('proxyquire')
11
11
 
12
+ process.removeAllListeners('warning')
13
+
14
+ let localhost
15
+ before(async function () {
16
+ [localhost] = await helper.getLoopbackHost()
17
+ })
18
+
12
19
  test('Should register a versioned route', t => {
13
20
  t.plan(11)
14
21
  const fastify = Fastify()
@@ -433,7 +440,7 @@ test('test log stream', t => {
433
440
  const stream = split(JSON.parse)
434
441
  const fastify = Fastify({
435
442
  logger: {
436
- stream: stream,
443
+ stream,
437
444
  level: 'info'
438
445
  }
439
446
  })
@@ -442,12 +449,12 @@ test('test log stream', t => {
442
449
  reply.send(new Error('kaboom'))
443
450
  })
444
451
 
445
- fastify.listen(0, err => {
452
+ fastify.listen(0, localhost, err => {
446
453
  t.error(err)
447
454
  fastify.server.unref()
448
455
 
449
456
  http.get({
450
- hostname: 'localhost',
457
+ hostname: fastify.server.address().hostname,
451
458
  port: fastify.server.address().port,
452
459
  path: '/',
453
460
  method: 'GET',
@@ -549,7 +556,7 @@ test('Should register a versioned route with custom versioning strategy', t => {
549
556
  })
550
557
 
551
558
  test('Should get error using an invalid a versioned route, using default validation (deprecated versioning option)', t => {
552
- t.plan(1)
559
+ t.plan(3)
553
560
 
554
561
  const fastify = Fastify({
555
562
  versioning: {
@@ -577,15 +584,19 @@ test('Should get error using an invalid a versioned route, using default validat
577
584
  }
578
585
  })
579
586
 
580
- fastify.route({
581
- method: 'GET',
582
- url: '/',
583
- // not a string version
584
- constraints: { version: 2 },
585
- handler: (req, reply) => {
586
- reply.send({ hello: 'cant match route v2' })
587
- }
588
- })
587
+ try {
588
+ fastify.route({
589
+ method: 'GET',
590
+ url: '/',
591
+ // not a string version
592
+ constraints: { version: 2 },
593
+ handler: (req, reply) => {
594
+ reply.send({ hello: 'cant match route v2' })
595
+ }
596
+ })
597
+ } catch (err) {
598
+ t.equal(err.message, 'Version constraint should be a string.')
599
+ }
589
600
 
590
601
  fastify.inject({
591
602
  method: 'GET',
@@ -594,7 +605,8 @@ test('Should get error using an invalid a versioned route, using default validat
594
605
  Accept: 'application/vnd.example.api+json;version=2'
595
606
  }
596
607
  }, (err, res) => {
597
- t.equal(err.message, 'Version constraint should be a string.')
608
+ t.error(err)
609
+ t.equal(res.statusCode, 404)
598
610
  })
599
611
  })
600
612
 
@@ -663,7 +675,7 @@ test('Should trigger a warning when a versioned route is registered via version
663
675
  }
664
676
 
665
677
  const route = proxyquire('../lib/route', { './warnings': warning })
666
- const fastify = proxyquire('..', { './lib/route.js': route })()
678
+ const fastify = proxyquire('..', { './lib/route.js': route })({ exposeHeadRoutes: false })
667
679
 
668
680
  fastify.route({
669
681
  method: 'GET',
@@ -2,21 +2,22 @@
2
2
 
3
3
  const t = require('tap')
4
4
  const test = t.test
5
- const { kReplySentOverwritten } = require('../lib/symbols')
5
+ const { kReplyHijacked } = require('../lib/symbols')
6
6
  const wrapThenable = require('../lib/wrapThenable')
7
+ const Reply = require('../lib/reply')
7
8
 
8
- test('should resolve immediately when reply[kReplySentOverwritten] is true', t => {
9
+ test('should resolve immediately when reply[kReplyHijacked] is true', t => {
9
10
  const reply = {}
10
- reply[kReplySentOverwritten] = true
11
+ reply[kReplyHijacked] = true
11
12
  const thenable = Promise.resolve()
12
13
  wrapThenable(thenable, reply)
13
14
  t.end()
14
15
  })
15
16
 
16
- test('should reject immediately when reply[kReplySentOverwritten] is true', t => {
17
+ test('should reject immediately when reply[kReplyHijacked] is true', t => {
17
18
  t.plan(1)
18
- const reply = { res: {} }
19
- reply[kReplySentOverwritten] = true
19
+ const reply = new Reply({}, {}, {})
20
+ reply[kReplyHijacked] = true
20
21
  reply.log = {
21
22
  error: ({ err }) => {
22
23
  t.equal(err.message, 'Reply sent already')
@@ -31,7 +31,7 @@
31
31
  "files": ["*.test-d.ts"],
32
32
  "rules": {
33
33
  "no-unused-vars": "off",
34
- "node/handle-callback-err": "off",
34
+ "n/handle-callback-err": "off",
35
35
  "@typescript-eslint/no-empty-function": "off",
36
36
  "@typescript-eslint/explicit-function-return-type": "off",
37
37
  "@typescript-eslint/no-unused-vars": "off",
@@ -1,6 +1,8 @@
1
1
  import { RawServerBase, RawServerDefault, RawRequestDefaultExpression } from './utils'
2
2
  import { FastifyRequest } from './request'
3
3
  import { RouteGenericInterface } from './route'
4
+ import { FastifyTypeProvider, FastifyTypeProviderDefault } from './type-provider'
5
+ import { FastifySchema } from './schema'
4
6
 
5
7
  type ContentTypeParserDoneFunction = (err: Error | null, body?: any) => void
6
8
 
@@ -12,8 +14,10 @@ export type FastifyBodyParser<
12
14
  RawServer extends RawServerBase = RawServerDefault,
13
15
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
14
16
  RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
15
- > = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, rawBody: RawBody, done: ContentTypeParserDoneFunction) => void)
16
- | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, rawBody: RawBody) => Promise<any>)
17
+ SchemaCompiler extends FastifySchema = FastifySchema,
18
+ TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
19
+ > = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, rawBody: RawBody, done: ContentTypeParserDoneFunction) => void)
20
+ | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, rawBody: RawBody) => Promise<any>)
17
21
 
18
22
  /**
19
23
  * Content Type Parser method that operates on request content
@@ -22,31 +26,36 @@ export type FastifyContentTypeParser<
22
26
  RawServer extends RawServerBase = RawServerDefault,
23
27
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
24
28
  RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
25
- > = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, payload: RawRequest) => Promise<any>)
26
- | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest>, payload: RawRequest, done: ContentTypeParserDoneFunction) => void)
29
+ SchemaCompiler extends FastifySchema = FastifySchema,
30
+ TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
31
+ > = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, payload: RawRequest) => Promise<any>)
32
+ | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, payload: RawRequest, done: ContentTypeParserDoneFunction) => void)
27
33
 
28
34
  /**
29
35
  * Natively, Fastify only supports 'application/json' and 'text/plain' content types. The default charset is utf-8. If you need to support different content types, you can use the addContentTypeParser API. The default JSON and/or plain text parser can be changed.
30
36
  */
31
37
  export interface AddContentTypeParser<
32
38
  RawServer extends RawServerBase = RawServerDefault,
33
- RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>
39
+ RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
40
+ RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
41
+ SchemaCompiler extends FastifySchema = FastifySchema,
42
+ TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
34
43
  > {
35
44
  (
36
45
  contentType: string | string[] | RegExp,
37
46
  opts: {
38
47
  bodyLimit?: number;
39
48
  },
40
- parser: FastifyContentTypeParser<RawServer, RawRequest>
49
+ parser: FastifyContentTypeParser<RawServer, RawRequest, RouteGeneric, SchemaCompiler, TypeProvider>
41
50
  ): void;
42
- (contentType: string | string[] | RegExp, parser: FastifyContentTypeParser<RawServer, RawRequest>): void;
51
+ (contentType: string | string[] | RegExp, parser: FastifyContentTypeParser<RawServer, RawRequest, RouteGeneric, SchemaCompiler, TypeProvider>): void;
43
52
  <parseAs extends string | Buffer>(
44
53
  contentType: string | string[] | RegExp,
45
54
  opts: {
46
55
  parseAs: parseAs extends Buffer ? 'buffer' : 'string';
47
56
  bodyLimit?: number;
48
57
  },
49
- parser: FastifyBodyParser<parseAs, RawServer, RawRequest>
58
+ parser: FastifyBodyParser<parseAs, RawServer, RawRequest, RouteGeneric, SchemaCompiler, TypeProvider>
50
59
  ): void;
51
60
  }
52
61