fastify 2.7.1 → 2.11.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 (72) hide show
  1. package/README.md +15 -4
  2. package/build/build-validation.js +8 -0
  3. package/docs/Benchmarking.md +2 -2
  4. package/docs/ContentTypeParser.md +12 -10
  5. package/docs/Decorators.md +14 -14
  6. package/docs/Ecosystem.md +7 -1
  7. package/docs/Errors.md +13 -8
  8. package/docs/Fluent-Schema.md +9 -12
  9. package/docs/Getting-Started.md +29 -25
  10. package/docs/HTTP2.md +1 -1
  11. package/docs/Hooks.md +201 -186
  12. package/docs/LTS.md +6 -7
  13. package/docs/Logging.md +10 -10
  14. package/docs/Middleware.md +59 -0
  15. package/docs/Plugins-Guide.md +52 -52
  16. package/docs/Plugins.md +3 -0
  17. package/docs/Reply.md +47 -3
  18. package/docs/Routes.md +120 -8
  19. package/docs/Server.md +69 -3
  20. package/docs/Serverless.md +76 -4
  21. package/docs/TypeScript.md +33 -10
  22. package/docs/Validation-and-Serialization.md +137 -1
  23. package/examples/typescript-server.ts +1 -1
  24. package/fastify.d.ts +52 -13
  25. package/fastify.js +68 -7
  26. package/lib/configValidator.js +99 -52
  27. package/lib/contentTypeParser.js +4 -4
  28. package/lib/context.js +2 -1
  29. package/lib/errors.js +21 -18
  30. package/lib/fourOhFour.js +10 -10
  31. package/lib/handleRequest.js +1 -2
  32. package/lib/logger.js +2 -2
  33. package/lib/pluginUtils.js +32 -0
  34. package/lib/reply.js +41 -6
  35. package/lib/route.js +37 -9
  36. package/lib/schemas.js +23 -12
  37. package/lib/symbols.js +4 -1
  38. package/lib/validation.js +15 -9
  39. package/lib/wrapThenable.js +1 -1
  40. package/package.json +34 -26
  41. package/test/404s.test.js +41 -1
  42. package/test/async-await.js +66 -0
  43. package/test/custom-parser.test.js +1 -1
  44. package/test/custom-querystring-parser.test.js +1 -1
  45. package/test/decorator.test.js +48 -0
  46. package/test/emit-warning.test.js +3 -3
  47. package/test/fastify-instance.test.js +29 -0
  48. package/test/helper.js +7 -7
  49. package/test/hooks-async.js +4 -3
  50. package/test/hooks.test.js +27 -8
  51. package/test/input-validation.test.js +126 -0
  52. package/test/internals/errors.test.js +9 -1
  53. package/test/internals/initialConfig.test.js +4 -2
  54. package/test/internals/plugin.test.js +4 -4
  55. package/test/internals/reply.test.js +78 -6
  56. package/test/internals/schemas.test.js +30 -0
  57. package/test/internals/validation.test.js +18 -0
  58. package/test/listen.test.js +1 -1
  59. package/test/logger.test.js +314 -1
  60. package/test/plugin.test.js +171 -0
  61. package/test/promises.test.js +55 -0
  62. package/test/proto-poisoning.test.js +76 -0
  63. package/test/route-hooks.test.js +109 -91
  64. package/test/route-prefix.test.js +1 -1
  65. package/test/schemas.test.js +450 -0
  66. package/test/shared-schemas.test.js +2 -2
  67. package/test/stream.test.js +10 -6
  68. package/test/throw.test.js +48 -2
  69. package/test/types/index.ts +86 -1
  70. package/test/validation-error-handling.test.js +3 -3
  71. package/test/versioned-routes.test.js +1 -1
  72. package/docs/Middlewares.md +0 -59
@@ -3,15 +3,23 @@
3
3
  const test = require('tap').test
4
4
  const Fastify = require('../')
5
5
 
6
- function testHook (hook) {
6
+ function endMiddleware (nextOrPayload, next) {
7
+ if (typeof nextOrPayload === 'function') {
8
+ nextOrPayload()
9
+ } else {
10
+ next()
11
+ }
12
+ }
13
+
14
+ function testExecutionHook (hook) {
7
15
  test(`${hook}`, t => {
8
16
  t.plan(3)
9
17
  const fastify = Fastify()
10
18
 
11
19
  fastify.post('/', {
12
- [hook]: (req, reply, done) => {
20
+ [hook]: (req, reply, nextOrPayload, next) => {
13
21
  t.pass('hook called')
14
- done()
22
+ endMiddleware(nextOrPayload, next)
15
23
  }
16
24
  }, (req, reply) => {
17
25
  reply.send(req.body)
@@ -29,22 +37,55 @@ function testHook (hook) {
29
37
  })
30
38
 
31
39
  test(`${hook} option should be called after ${hook} hook`, t => {
32
- t.plan(2)
40
+ t.plan(3)
33
41
  const fastify = Fastify()
34
- let check = ''
42
+ const checker = Object.defineProperty({ calledTimes: 0 }, 'check', {
43
+ get: function () { return ++this.calledTimes }
44
+ })
35
45
 
36
- fastify.addHook(hook, (req, reply, next) => {
37
- check = 'a'
38
- next()
46
+ fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
47
+ t.equal(checker.check, 1)
48
+ endMiddleware(nextOrPayload, next)
39
49
  })
40
50
 
41
51
  fastify.post('/', {
42
- [hook]: (req, reply, done) => {
43
- check += 'b'
44
- done()
52
+ [hook]: (req, reply, nextOrPayload, next) => {
53
+ t.equal(checker.check, 2)
54
+ endMiddleware(nextOrPayload, next)
45
55
  }
46
56
  }, (req, reply) => {
47
- reply.send({ check })
57
+ reply.send({})
58
+ })
59
+
60
+ fastify.inject({
61
+ method: 'POST',
62
+ url: '/',
63
+ payload: { hello: 'world' }
64
+ }, (err, res) => {
65
+ t.error(err)
66
+ })
67
+ })
68
+
69
+ test(`${hook} option could accept an array of functions`, t => {
70
+ t.plan(3)
71
+ const fastify = Fastify()
72
+ const checker = Object.defineProperty({ calledTimes: 0 }, 'check', {
73
+ get: function () { return ++this.calledTimes }
74
+ })
75
+
76
+ fastify.post('/', {
77
+ [hook]: [
78
+ (req, reply, nextOrPayload, next) => {
79
+ t.equal(checker.check, 1)
80
+ endMiddleware(nextOrPayload, next)
81
+ },
82
+ (req, reply, nextOrPayload, next) => {
83
+ t.equal(checker.check, 2)
84
+ endMiddleware(nextOrPayload, next)
85
+ }
86
+ ]
87
+ }, (req, reply) => {
88
+ reply.send({})
48
89
  })
49
90
 
50
91
  fastify.inject({
@@ -53,11 +94,55 @@ function testHook (hook) {
53
94
  payload: { hello: 'world' }
54
95
  }, (err, res) => {
55
96
  t.error(err)
56
- var payload = JSON.parse(res.payload)
57
- t.deepEqual(payload, { check: 'ab' })
58
97
  })
59
98
  })
60
99
 
100
+ test(`${hook} option does not interfere with ${hook} hook`, t => {
101
+ t.plan(7)
102
+ const fastify = Fastify()
103
+ const checker = Object.defineProperty({ calledTimes: 0 }, 'check', {
104
+ get: function () { return ++this.calledTimes }
105
+ })
106
+
107
+ fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
108
+ t.equal(checker.check, 1)
109
+ endMiddleware(nextOrPayload, next)
110
+ })
111
+
112
+ fastify.post('/', {
113
+ [hook]: (req, reply, nextOrPayload, next) => {
114
+ t.equal(checker.check, 2)
115
+ endMiddleware(nextOrPayload, next)
116
+ }
117
+ }, handler)
118
+
119
+ fastify.post('/no', handler)
120
+
121
+ function handler (req, reply) {
122
+ reply.send({})
123
+ }
124
+
125
+ fastify.inject({
126
+ method: 'post',
127
+ url: '/'
128
+ }, (err, res) => {
129
+ t.error(err)
130
+ t.equal(checker.calledTimes, 2)
131
+
132
+ checker.calledTimes = 0
133
+
134
+ fastify.inject({
135
+ method: 'post',
136
+ url: '/no'
137
+ }, (err, res) => {
138
+ t.error(err)
139
+ t.equal(checker.calledTimes, 1)
140
+ })
141
+ })
142
+ })
143
+ }
144
+
145
+ function testBeforeHandlerHook (hook) {
61
146
  test(`${hook} option should be unique per route`, t => {
62
147
  t.plan(4)
63
148
  const fastify = Fastify()
@@ -153,79 +238,6 @@ function testHook (hook) {
153
238
  })
154
239
  })
155
240
 
156
- test(`${hook} option could accept an array of functions`, t => {
157
- t.plan(2)
158
- const fastify = Fastify()
159
-
160
- fastify.post('/', {
161
- [hook]: [
162
- (req, reply, done) => {
163
- req.aa = 'a'
164
- done()
165
- },
166
- (req, reply, done) => {
167
- req.aa += 'b'
168
- done()
169
- }
170
- ]
171
- }, (req, reply) => {
172
- reply.send({ aa: req.aa })
173
- })
174
-
175
- fastify.inject({
176
- method: 'POST',
177
- url: '/',
178
- payload: { hello: 'world' }
179
- }, (err, res) => {
180
- t.error(err)
181
- var payload = JSON.parse(res.payload)
182
- t.deepEqual(payload, { aa: 'ab' })
183
- })
184
- })
185
-
186
- test(`${hook} option does not interfere with ${hook} hook`, t => {
187
- t.plan(4)
188
- const fastify = Fastify()
189
-
190
- fastify.addHook(hook, (req, reply, next) => {
191
- req.check = 'a'
192
- next()
193
- })
194
-
195
- fastify.post('/', {
196
- [hook]: (req, reply, done) => {
197
- req.check += 'b'
198
- done()
199
- }
200
- }, handler)
201
-
202
- fastify.post('/no', handler)
203
-
204
- function handler (req, reply) {
205
- reply.send({ check: req.check })
206
- }
207
-
208
- fastify.inject({
209
- method: 'post',
210
- url: '/',
211
- payload: { hello: 'world' }
212
- }, (err, res) => {
213
- t.error(err)
214
- var payload = JSON.parse(res.payload)
215
- t.deepEqual(payload, { check: 'ab' })
216
- })
217
-
218
- fastify.inject({
219
- method: 'post',
220
- url: '/no',
221
- payload: { hello: 'world' }
222
- }, (err, res) => {
223
- t.error(err)
224
- var payload = JSON.parse(res.payload)
225
- t.deepEqual(payload, { check: 'a' })
226
- })
227
- })
228
-
229
241
  test(`${hook} option should keep the context`, t => {
230
242
  t.plan(3)
231
243
  const fastify = Fastify()
@@ -281,11 +293,17 @@ function testHook (hook) {
281
293
  })
282
294
  }
283
295
 
296
+ testExecutionHook('preHandler')
297
+ testExecutionHook('onSend')
298
+ testExecutionHook('onRequest')
299
+ testExecutionHook('onResponse')
300
+ testExecutionHook('preValidation')
301
+ testExecutionHook('preParsing')
284
302
  // hooks that comes before the handler
285
- testHook('preHandler')
286
- testHook('onRequest')
287
- testHook('preValidation')
288
- testHook('preParsing')
303
+ testBeforeHandlerHook('preHandler')
304
+ testBeforeHandlerHook('onRequest')
305
+ testBeforeHandlerHook('preValidation')
306
+ testBeforeHandlerHook('preParsing')
289
307
 
290
308
  test('preHandler backwards compatibility with beforeHandler option (should emit a warning)', t => {
291
309
  t.plan(4)
@@ -484,7 +484,7 @@ test('returns 404 status code with /prefix/ and / route - prefixTrailingSlash: "
484
484
  t.error(err)
485
485
  t.same(JSON.parse(res.payload), {
486
486
  error: 'Not Found',
487
- message: 'Not Found',
487
+ message: 'Route GET:/prefix// not found',
488
488
  statusCode: 404
489
489
  })
490
490
  })
@@ -0,0 +1,450 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const Fastify = require('..')
6
+
7
+ const ajvMergePatch = require('ajv-merge-patch')
8
+ const AJV = require('ajv')
9
+ const fastClone = require('rfdc')({ circles: false, proto: true })
10
+
11
+ const schemaUsed = {
12
+ $id: 'urn:schema:foo',
13
+ definitions: {
14
+ foo: { type: 'string' }
15
+ },
16
+ type: 'object',
17
+ properties: {
18
+ foo: { $ref: '#/definitions/foo' }
19
+ }
20
+ }
21
+ const schemaParent = {
22
+ $id: 'urn:schema:response',
23
+ type: 'object',
24
+ required: ['foo'],
25
+ properties: {
26
+ foo: { $ref: 'urn:schema:foo#/definitions/foo' }
27
+ }
28
+ }
29
+
30
+ const schemaRequest = {
31
+ $id: 'urn:schema:request',
32
+ type: 'object',
33
+ required: ['foo'],
34
+ properties: {
35
+ foo: { $ref: 'urn:schema:response#/properties/foo' }
36
+ }
37
+ }
38
+
39
+ test('Should use the ref resolver - response', t => {
40
+ t.plan(2)
41
+ const fastify = Fastify()
42
+ const ajv = new AJV()
43
+ ajv.addSchema(fastClone(schemaParent))
44
+ ajv.addSchema(fastClone(schemaUsed))
45
+
46
+ fastify.setSchemaCompiler(schema => ajv.compile(schema))
47
+ fastify.setSchemaResolver((ref) => {
48
+ t.equals(ref, 'urn:schema:foo')
49
+ return ajv.getSchema(ref).schema
50
+ })
51
+
52
+ fastify.route({
53
+ method: 'GET',
54
+ url: '/',
55
+ schema: {
56
+ response: {
57
+ '2xx': ajv.getSchema('urn:schema:response').schema
58
+ }
59
+ },
60
+ handler (req, reply) {
61
+ reply.send({ foo: 'bar' })
62
+ }
63
+ })
64
+
65
+ fastify.ready(t.error)
66
+ })
67
+
68
+ test('Should use the ref resolver - body', t => {
69
+ t.plan(3)
70
+ const fastify = Fastify()
71
+ const ajv = new AJV()
72
+ ajv.addSchema(fastClone(schemaParent))
73
+ ajv.addSchema(fastClone(schemaUsed))
74
+
75
+ fastify.setSchemaCompiler(schema => ajv.compile(schema))
76
+ fastify.setSchemaResolver((ref) => {
77
+ t.equals(ref, 'urn:schema:foo')
78
+ return ajv.getSchema(ref).schema
79
+ })
80
+
81
+ fastify.route({
82
+ method: 'POST',
83
+ url: '/',
84
+ schema: {
85
+ body: ajv.getSchema('urn:schema:response').schema
86
+ },
87
+ handler (req, reply) {
88
+ reply.send({ foo: 'bar' })
89
+ }
90
+ })
91
+
92
+ fastify.inject({
93
+ method: 'POST',
94
+ url: '/',
95
+ payload: { foo: 'bar' }
96
+ }, (err, res) => {
97
+ t.error(err)
98
+ t.deepEquals(JSON.parse(res.payload), { foo: 'bar' })
99
+ })
100
+ })
101
+
102
+ test('Encapsulation', t => {
103
+ t.plan(14)
104
+ const fastify = Fastify()
105
+ const ajv = new AJV()
106
+ ajv.addSchema(fastClone(schemaParent))
107
+ ajv.addSchema(fastClone(schemaUsed))
108
+
109
+ fastify.register((instance, opts, next) => {
110
+ instance.setSchemaCompiler(schema => ajv.compile(schema))
111
+ instance.setSchemaResolver((ref) => {
112
+ return ajv.getSchema(ref).schema
113
+ })
114
+ instance.route({
115
+ method: 'POST',
116
+ url: '/',
117
+ schema: {
118
+ body: ajv.getSchema('urn:schema:response').schema
119
+ },
120
+ handler (req, reply) {
121
+ reply.send({ foo: 'bar' })
122
+ }
123
+ })
124
+
125
+ instance.register((instance, opts, next) => {
126
+ instance.route({
127
+ method: 'POST',
128
+ url: '/two',
129
+ schema: {
130
+ body: ajv.getSchema('urn:schema:response').schema
131
+ },
132
+ handler (req, reply) {
133
+ reply.send({ foo: 'bar' })
134
+ }
135
+ })
136
+ next()
137
+ })
138
+ next()
139
+ })
140
+
141
+ fastify.register((instance, opts, next) => {
142
+ instance.route({
143
+ method: 'POST',
144
+ url: '/clean',
145
+ handler (req, reply) {
146
+ reply.send({ foo: 'bar' })
147
+ }
148
+ })
149
+ next()
150
+ })
151
+
152
+ fastify.ready(err => {
153
+ t.error(err)
154
+
155
+ fastify.inject({
156
+ method: 'POST',
157
+ url: '/',
158
+ payload: { foo: 'bar' }
159
+ }, (err, res) => {
160
+ t.error(err)
161
+ t.equals(res.statusCode, 200)
162
+ t.deepEquals(JSON.parse(res.payload), { foo: 'bar' })
163
+ })
164
+
165
+ fastify.inject({
166
+ method: 'POST',
167
+ url: '/',
168
+ payload: { wrongFoo: 'bar' }
169
+ }, (err, res) => {
170
+ t.error(err)
171
+ t.equals(res.statusCode, 400)
172
+ })
173
+
174
+ fastify.inject({
175
+ method: 'POST',
176
+ url: '/two',
177
+ payload: { foo: 'bar' }
178
+ }, (err, res) => {
179
+ t.error(err)
180
+ t.equals(res.statusCode, 200)
181
+ t.deepEquals(JSON.parse(res.payload), { foo: 'bar' })
182
+ })
183
+
184
+ fastify.inject({
185
+ method: 'POST',
186
+ url: '/two',
187
+ payload: { wrongFoo: 'bar' }
188
+ }, (err, res) => {
189
+ t.error(err)
190
+ t.equals(res.statusCode, 400)
191
+ })
192
+
193
+ fastify.inject({
194
+ method: 'POST',
195
+ url: '/clean',
196
+ payload: { wrongFoo: 'bar' }
197
+ }, (err, res) => {
198
+ t.error(err)
199
+ t.equals(res.statusCode, 200)
200
+ t.deepEquals(JSON.parse(res.payload), { foo: 'bar' })
201
+ })
202
+ })
203
+ })
204
+
205
+ test('Schema resolver without schema compiler', t => {
206
+ t.plan(2)
207
+ const fastify = Fastify()
208
+
209
+ fastify.setSchemaResolver(() => { t.fail('the schema resolver will never be called') })
210
+ fastify.route({
211
+ method: 'POST',
212
+ url: '/',
213
+ schema: {},
214
+ handler (req, reply) {
215
+ reply.send({ foo: 'bar' })
216
+ }
217
+ })
218
+
219
+ fastify.ready(err => {
220
+ t.is(err.code, 'FST_ERR_SCH_MISSING_COMPILER')
221
+ t.isLike(err.message, /You must provide a schemaCompiler to route POST \/ to use the schemaResolver/)
222
+ })
223
+ })
224
+
225
+ test('Triple $ref deep', t => {
226
+ t.plan(6)
227
+
228
+ const fastify = Fastify()
229
+ const ajv = new AJV()
230
+ ajv.addSchema(fastClone(schemaParent))
231
+ ajv.addSchema(fastClone(schemaUsed))
232
+ ajv.addSchema(fastClone(schemaRequest))
233
+
234
+ fastify.setSchemaCompiler(schema => ajv.compile(schema))
235
+ fastify.setSchemaResolver((ref) => {
236
+ return ajv.getSchema(ref).schema
237
+ })
238
+
239
+ fastify.route({
240
+ method: 'POST',
241
+ url: '/',
242
+ schema: {
243
+ body: ajv.getSchema('urn:schema:request').schema,
244
+ response: {
245
+ '2xx': ajv.getSchema('urn:schema:response').schema
246
+ }
247
+ },
248
+ handler (req, reply) {
249
+ reply.send({ foo: 'bar' })
250
+ }
251
+ })
252
+
253
+ fastify.inject({
254
+ method: 'POST',
255
+ url: '/',
256
+ payload: { foo: 'bar' }
257
+ }, (err, res) => {
258
+ t.error(err)
259
+ t.equals(res.statusCode, 200)
260
+ t.deepEquals(JSON.parse(res.payload), { foo: 'bar' })
261
+ })
262
+
263
+ fastify.inject({
264
+ method: 'POST',
265
+ url: '/',
266
+ payload: { fool: 'bar' }
267
+ }, (err, res) => {
268
+ t.error(err)
269
+ t.equals(res.statusCode, 400)
270
+ t.deepEquals(JSON.parse(res.payload).message, "body should have required property 'foo'")
271
+ })
272
+ })
273
+
274
+ test('$ref with a simple $id', t => {
275
+ t.plan(4)
276
+ const fastify = Fastify()
277
+ const ajv = new AJV()
278
+ ajv.addSchema(fastClone(schemaUsed))
279
+ ajv.addSchema({
280
+ $id: 'urn:schema:response',
281
+ type: 'object',
282
+ required: ['foo'],
283
+ properties: {
284
+ foo: { $ref: 'urn:schema:foo' }
285
+ }
286
+ })
287
+ ajv.addSchema({
288
+ $id: 'urn:schema:request',
289
+ type: 'object',
290
+ required: ['foo'],
291
+ properties: {
292
+ foo: { $ref: 'urn:schema:foo' }
293
+ }
294
+ })
295
+
296
+ fastify.setSchemaCompiler(schema => ajv.compile(schema))
297
+ fastify.setSchemaResolver((ref) => {
298
+ t.equals(ref, 'urn:schema:foo')
299
+ return ajv.getSchema(ref).schema
300
+ })
301
+
302
+ fastify.route({
303
+ method: 'POST',
304
+ url: '/',
305
+ schema: {
306
+ body: ajv.getSchema('urn:schema:request').schema,
307
+ response: {
308
+ '2xx': ajv.getSchema('urn:schema:response').schema
309
+ }
310
+ },
311
+ handler (req, reply) {
312
+ reply.send({ foo: { foo: 'bar', bar: 'foo' } })
313
+ }
314
+ })
315
+
316
+ fastify.inject({
317
+ method: 'POST',
318
+ url: '/',
319
+ payload: { foo: { foo: 'bar' } }
320
+ }, (err, res) => {
321
+ t.error(err)
322
+ t.equals(res.statusCode, 200)
323
+ t.deepEquals(JSON.parse(res.payload), { foo: { foo: 'bar' } })
324
+ })
325
+ })
326
+
327
+ test('Should handle root $merge keywords in header', t => {
328
+ t.plan(5)
329
+ const fastify = Fastify({
330
+ ajv: {
331
+ plugins: [
332
+ ajvMergePatch
333
+ ]
334
+ }
335
+ })
336
+
337
+ fastify.route({
338
+ method: 'GET',
339
+ url: '/',
340
+ schema: {
341
+ headers: {
342
+ $merge: {
343
+ source: {
344
+ type: 'object',
345
+ properties: {
346
+ q: {
347
+ type: 'string'
348
+ }
349
+ }
350
+ },
351
+ with: {
352
+ required: ['q']
353
+ }
354
+ }
355
+ }
356
+ },
357
+ handler (req, reply) {
358
+ reply.send({ ok: 1 })
359
+ }
360
+ })
361
+
362
+ fastify.ready(err => {
363
+ t.error(err)
364
+
365
+ fastify.inject({
366
+ method: 'GET',
367
+ url: '/'
368
+ }, (err, res) => {
369
+ t.error(err)
370
+ t.equals(res.statusCode, 400)
371
+ })
372
+
373
+ fastify.inject({
374
+ method: 'GET',
375
+ url: '/',
376
+ headers: {
377
+ q: 'foo'
378
+ }
379
+ }, (err, res) => {
380
+ t.error(err)
381
+ t.equals(res.statusCode, 200)
382
+ })
383
+ })
384
+ })
385
+
386
+ test('Should handle root $patch keywords in header', t => {
387
+ t.plan(5)
388
+ const fastify = Fastify({
389
+ ajv: {
390
+ plugins: [
391
+ ajvMergePatch
392
+ ]
393
+ }
394
+ })
395
+
396
+ fastify.route({
397
+ method: 'GET',
398
+ url: '/',
399
+ schema: {
400
+ headers: {
401
+ $patch: {
402
+ source: {
403
+ type: 'object',
404
+ properties: {
405
+ q: {
406
+ type: 'string'
407
+ }
408
+ }
409
+ },
410
+ with: [
411
+ {
412
+ op: 'add',
413
+ path: '/properties/q',
414
+ value: { type: 'number' }
415
+ }
416
+ ]
417
+ }
418
+ }
419
+ },
420
+ handler (req, reply) {
421
+ reply.send({ ok: 1 })
422
+ }
423
+ })
424
+
425
+ fastify.ready(err => {
426
+ t.error(err)
427
+
428
+ fastify.inject({
429
+ method: 'GET',
430
+ url: '/',
431
+ headers: {
432
+ q: 'foo'
433
+ }
434
+ }, (err, res) => {
435
+ t.error(err)
436
+ t.equals(res.statusCode, 400)
437
+ })
438
+
439
+ fastify.inject({
440
+ method: 'GET',
441
+ url: '/',
442
+ headers: {
443
+ q: 10
444
+ }
445
+ }, (err, res) => {
446
+ t.error(err)
447
+ t.equals(res.statusCode, 200)
448
+ })
449
+ })
450
+ })
@@ -701,7 +701,7 @@ test('The schema resolver should clean the $id key before passing it to the comp
701
701
  url: '/',
702
702
  method: 'GET',
703
703
  schema: {
704
- description: `get`,
704
+ description: 'get',
705
705
  body: 'second#',
706
706
  response: {
707
707
  200: 'second#'
@@ -716,7 +716,7 @@ test('The schema resolver should clean the $id key before passing it to the comp
716
716
  url: '/',
717
717
  method: 'PATCH',
718
718
  schema: {
719
- description: `patch`,
719
+ description: 'patch',
720
720
  body: 'first#',
721
721
  response: {
722
722
  200: 'first#'