fastify 4.2.1 → 4.3.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/docs/Guides/Ecosystem.md +2 -0
- package/docs/Reference/HTTP2.md +1 -3
- package/docs/Reference/Reply.md +176 -0
- package/docs/Reference/Request.md +171 -0
- package/fastify.d.ts +1 -1
- package/fastify.js +2 -2
- package/lib/contentTypeParser.js +10 -2
- package/lib/context.js +10 -1
- package/lib/errors.js +8 -0
- package/lib/reply.js +80 -2
- package/lib/request.js +97 -1
- package/lib/route.js +2 -0
- package/lib/symbols.js +15 -9
- package/package.json +1 -1
- package/test/content-parser.test.js +15 -0
- package/test/internals/reply-serialize.test.js +583 -0
- package/test/internals/request-validate.test.js +1269 -0
- package/test/internals/request.test.js +11 -2
- package/test/request-error.test.js +44 -1
- package/test/types/hooks.test-d.ts +1 -2
- package/test/types/import.ts +1 -1
- package/test/types/request.test-d.ts +1 -1
- package/test/types/type-provider.test-d.ts +76 -6
- package/types/hooks.d.ts +19 -39
- package/types/instance.d.ts +19 -39
- package/types/reply.d.ts +5 -0
- package/types/request.d.ts +16 -3
- package/types/route.d.ts +23 -29
- package/types/type-provider.d.ts +7 -6
|
@@ -0,0 +1,1269 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Ajv = require('ajv')
|
|
5
|
+
const { kRequestValidateWeakMap } = require('../../lib/symbols')
|
|
6
|
+
const Fastify = require('../../fastify')
|
|
7
|
+
|
|
8
|
+
const defaultSchema = {
|
|
9
|
+
type: 'object',
|
|
10
|
+
required: ['hello'],
|
|
11
|
+
properties: {
|
|
12
|
+
hello: { type: 'string' },
|
|
13
|
+
world: { type: 'string' }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const requestSchema = {
|
|
18
|
+
params: {
|
|
19
|
+
id: {
|
|
20
|
+
type: 'integer',
|
|
21
|
+
minimum: 1
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
querystring: {
|
|
25
|
+
foo: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: ['bar']
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
body: defaultSchema,
|
|
31
|
+
headers: {
|
|
32
|
+
'x-foo': {
|
|
33
|
+
type: 'string'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
test('#compileValidationSchema', subtest => {
|
|
39
|
+
subtest.plan(5)
|
|
40
|
+
|
|
41
|
+
subtest.test('Should return a function - Route without schema', async t => {
|
|
42
|
+
const fastify = Fastify()
|
|
43
|
+
|
|
44
|
+
t.plan(3)
|
|
45
|
+
|
|
46
|
+
fastify.get('/', (req, reply) => {
|
|
47
|
+
const validate = req.compileValidationSchema(defaultSchema)
|
|
48
|
+
|
|
49
|
+
t.type(validate, Function)
|
|
50
|
+
t.ok(validate({ hello: 'world' }))
|
|
51
|
+
t.notOk(validate({ world: 'foo' }))
|
|
52
|
+
|
|
53
|
+
reply.send({ hello: 'world' })
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
await fastify.inject({
|
|
57
|
+
path: '/',
|
|
58
|
+
method: 'GET'
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
subtest.test(
|
|
63
|
+
'Should reuse the validate fn across multiple invocations - Route without schema',
|
|
64
|
+
async t => {
|
|
65
|
+
const fastify = Fastify()
|
|
66
|
+
let validate = null
|
|
67
|
+
let counter = 0
|
|
68
|
+
|
|
69
|
+
t.plan(16)
|
|
70
|
+
|
|
71
|
+
fastify.get('/', (req, reply) => {
|
|
72
|
+
counter++
|
|
73
|
+
if (counter > 1) {
|
|
74
|
+
const newValidate = req.compileValidationSchema(defaultSchema)
|
|
75
|
+
t.equal(validate, newValidate, 'Are the same validate function')
|
|
76
|
+
validate = newValidate
|
|
77
|
+
} else {
|
|
78
|
+
validate = req.compileValidationSchema(defaultSchema)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
t.type(validate, Function)
|
|
82
|
+
t.ok(validate({ hello: 'world' }))
|
|
83
|
+
t.notOk(validate({ world: 'foo' }))
|
|
84
|
+
|
|
85
|
+
reply.send({ hello: 'world' })
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
await Promise.all([
|
|
89
|
+
fastify.inject({
|
|
90
|
+
path: '/',
|
|
91
|
+
method: 'GET'
|
|
92
|
+
}),
|
|
93
|
+
fastify.inject({
|
|
94
|
+
path: '/',
|
|
95
|
+
method: 'GET'
|
|
96
|
+
}),
|
|
97
|
+
fastify.inject({
|
|
98
|
+
path: '/',
|
|
99
|
+
method: 'GET'
|
|
100
|
+
}),
|
|
101
|
+
fastify.inject({
|
|
102
|
+
path: '/',
|
|
103
|
+
method: 'GET'
|
|
104
|
+
})
|
|
105
|
+
])
|
|
106
|
+
|
|
107
|
+
t.equal(counter, 4)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
subtest.test('Should return a function - Route with schema', async t => {
|
|
112
|
+
const fastify = Fastify()
|
|
113
|
+
|
|
114
|
+
t.plan(3)
|
|
115
|
+
|
|
116
|
+
fastify.post(
|
|
117
|
+
'/',
|
|
118
|
+
{
|
|
119
|
+
schema: {
|
|
120
|
+
body: defaultSchema
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
(req, reply) => {
|
|
124
|
+
const validate = req.compileValidationSchema(defaultSchema)
|
|
125
|
+
|
|
126
|
+
t.type(validate, Function)
|
|
127
|
+
t.ok(validate({ hello: 'world' }))
|
|
128
|
+
t.notOk(validate({ world: 'foo' }))
|
|
129
|
+
|
|
130
|
+
reply.send({ hello: 'world' })
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
await fastify.inject({
|
|
135
|
+
path: '/',
|
|
136
|
+
method: 'POST',
|
|
137
|
+
payload: {
|
|
138
|
+
hello: 'world',
|
|
139
|
+
world: 'foo'
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
subtest.test(
|
|
145
|
+
'Should use the custom validator compiler for the route',
|
|
146
|
+
async t => {
|
|
147
|
+
const fastify = Fastify()
|
|
148
|
+
let called = 0
|
|
149
|
+
const custom = ({ schema, httpPart, url, method }) => {
|
|
150
|
+
t.equal(schema, defaultSchema)
|
|
151
|
+
t.equal(url, '/')
|
|
152
|
+
t.equal(method, 'GET')
|
|
153
|
+
t.equal(httpPart, 'querystring')
|
|
154
|
+
|
|
155
|
+
return input => {
|
|
156
|
+
called++
|
|
157
|
+
t.same(input, { hello: 'world' })
|
|
158
|
+
return true
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
t.plan(10)
|
|
163
|
+
|
|
164
|
+
fastify.get('/', { validatorCompiler: custom }, (req, reply) => {
|
|
165
|
+
const first = req.compileValidationSchema(defaultSchema, 'querystring')
|
|
166
|
+
const second = req.compileValidationSchema(defaultSchema, 'querystring')
|
|
167
|
+
|
|
168
|
+
t.equal(first, second)
|
|
169
|
+
t.ok(first({ hello: 'world' }))
|
|
170
|
+
t.ok(second({ hello: 'world' }))
|
|
171
|
+
t.equal(called, 2)
|
|
172
|
+
|
|
173
|
+
reply.send({ hello: 'world' })
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
await fastify.inject({
|
|
177
|
+
path: '/',
|
|
178
|
+
method: 'GET'
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
subtest.test(
|
|
184
|
+
'Should instantiate a WeakMap when executed for first time',
|
|
185
|
+
async t => {
|
|
186
|
+
const fastify = Fastify()
|
|
187
|
+
|
|
188
|
+
t.plan(5)
|
|
189
|
+
|
|
190
|
+
fastify.get('/', (req, reply) => {
|
|
191
|
+
t.equal(req.context[kRequestValidateWeakMap], null)
|
|
192
|
+
t.type(req.compileValidationSchema(defaultSchema), Function)
|
|
193
|
+
t.type(req.context[kRequestValidateWeakMap], WeakMap)
|
|
194
|
+
t.type(req.compileValidationSchema(Object.assign({}, defaultSchema)), Function)
|
|
195
|
+
t.type(req.context[kRequestValidateWeakMap], WeakMap)
|
|
196
|
+
|
|
197
|
+
reply.send({ hello: 'world' })
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
await fastify.inject({
|
|
201
|
+
path: '/',
|
|
202
|
+
method: 'GET'
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
test('#getValidationFunction', subtest => {
|
|
209
|
+
subtest.plan(4)
|
|
210
|
+
|
|
211
|
+
subtest.test('Should return a validation function', async t => {
|
|
212
|
+
const fastify = Fastify()
|
|
213
|
+
|
|
214
|
+
t.plan(1)
|
|
215
|
+
|
|
216
|
+
fastify.get('/', (req, reply) => {
|
|
217
|
+
const original = req.compileValidationSchema(defaultSchema)
|
|
218
|
+
const referenced = req.getValidationFunction(defaultSchema)
|
|
219
|
+
|
|
220
|
+
t.equal(original, referenced)
|
|
221
|
+
|
|
222
|
+
reply.send({ hello: 'world' })
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
await fastify.inject({
|
|
226
|
+
path: '/',
|
|
227
|
+
method: 'GET'
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
subtest.test('Should return undefined if no schema compiled', async t => {
|
|
232
|
+
const fastify = Fastify()
|
|
233
|
+
|
|
234
|
+
t.plan(2)
|
|
235
|
+
|
|
236
|
+
fastify.get('/', (req, reply) => {
|
|
237
|
+
const validate = req.getValidationFunction(defaultSchema)
|
|
238
|
+
t.notOk(validate)
|
|
239
|
+
|
|
240
|
+
const validateFn = req.getValidationFunction(42)
|
|
241
|
+
t.notOk(validateFn)
|
|
242
|
+
|
|
243
|
+
reply.send({ hello: 'world' })
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
await fastify.inject('/')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
subtest.test(
|
|
250
|
+
'Should return the validation function from each HTTP part',
|
|
251
|
+
async t => {
|
|
252
|
+
const fastify = Fastify()
|
|
253
|
+
let headerValidation = null
|
|
254
|
+
let customValidation = null
|
|
255
|
+
|
|
256
|
+
t.plan(15)
|
|
257
|
+
|
|
258
|
+
fastify.post(
|
|
259
|
+
'/:id',
|
|
260
|
+
{
|
|
261
|
+
schema: requestSchema
|
|
262
|
+
},
|
|
263
|
+
(req, reply) => {
|
|
264
|
+
const { params } = req
|
|
265
|
+
|
|
266
|
+
switch (params.id) {
|
|
267
|
+
case 1:
|
|
268
|
+
customValidation = req.compileValidationSchema(defaultSchema)
|
|
269
|
+
t.ok(req.getValidationFunction('body'))
|
|
270
|
+
t.ok(req.getValidationFunction('body')({ hello: 'world' }))
|
|
271
|
+
t.notOk(req.getValidationFunction('body')({ world: 'hello' }))
|
|
272
|
+
break
|
|
273
|
+
case 2:
|
|
274
|
+
headerValidation = req.getValidationFunction('headers')
|
|
275
|
+
t.ok(headerValidation)
|
|
276
|
+
t.ok(headerValidation({ 'x-foo': 'world' }))
|
|
277
|
+
t.notOk(headerValidation({ 'x-foo': [] }))
|
|
278
|
+
break
|
|
279
|
+
case 3:
|
|
280
|
+
t.ok(req.getValidationFunction('params'))
|
|
281
|
+
t.ok(req.getValidationFunction('params')({ id: 123 }))
|
|
282
|
+
t.notOk(req.getValidationFunction('params'({ id: 1.2 })))
|
|
283
|
+
break
|
|
284
|
+
case 4:
|
|
285
|
+
t.ok(req.getValidationFunction('querystring'))
|
|
286
|
+
t.ok(req.getValidationFunction('querystring')({ foo: 'bar' }))
|
|
287
|
+
t.notOk(
|
|
288
|
+
req.getValidationFunction('querystring')({ foo: 'not-bar' })
|
|
289
|
+
)
|
|
290
|
+
break
|
|
291
|
+
case 5:
|
|
292
|
+
t.equal(
|
|
293
|
+
customValidation,
|
|
294
|
+
req.getValidationFunction(defaultSchema)
|
|
295
|
+
)
|
|
296
|
+
t.ok(customValidation({ hello: 'world' }))
|
|
297
|
+
t.notOk(customValidation({}))
|
|
298
|
+
t.equal(headerValidation, req.getValidationFunction('headers'))
|
|
299
|
+
break
|
|
300
|
+
default:
|
|
301
|
+
t.fail('Invalid id')
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
reply.send({ hello: 'world' })
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
const promises = []
|
|
309
|
+
|
|
310
|
+
for (let i = 1; i < 6; i++) {
|
|
311
|
+
promises.push(
|
|
312
|
+
fastify.inject({
|
|
313
|
+
path: `/${i}`,
|
|
314
|
+
method: 'post',
|
|
315
|
+
query: { foo: 'bar' },
|
|
316
|
+
payload: {
|
|
317
|
+
hello: 'world'
|
|
318
|
+
},
|
|
319
|
+
headers: {
|
|
320
|
+
'x-foo': 'x-bar'
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
await Promise.all(promises)
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
subtest.test('Should not set a WeakMap if there is no schema', async t => {
|
|
331
|
+
const fastify = Fastify()
|
|
332
|
+
|
|
333
|
+
t.plan(1)
|
|
334
|
+
|
|
335
|
+
fastify.get('/', (req, reply) => {
|
|
336
|
+
req.getValidationFunction(defaultSchema)
|
|
337
|
+
req.getValidationFunction('body')
|
|
338
|
+
|
|
339
|
+
t.equal(req.context[kRequestValidateWeakMap], null)
|
|
340
|
+
reply.send({ hello: 'world' })
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
await fastify.inject({
|
|
344
|
+
path: '/',
|
|
345
|
+
method: 'GET'
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
test('#validate', subtest => {
|
|
351
|
+
subtest.plan(7)
|
|
352
|
+
|
|
353
|
+
subtest.test(
|
|
354
|
+
'Should return true/false if input valid - Route without schema',
|
|
355
|
+
async t => {
|
|
356
|
+
const fastify = Fastify()
|
|
357
|
+
|
|
358
|
+
t.plan(2)
|
|
359
|
+
|
|
360
|
+
fastify.get('/', (req, reply) => {
|
|
361
|
+
const isNotValid = req.validateInput({ world: 'string' }, defaultSchema)
|
|
362
|
+
const isValid = req.validateInput({ hello: 'string' }, defaultSchema)
|
|
363
|
+
|
|
364
|
+
t.notOk(isNotValid)
|
|
365
|
+
t.ok(isValid)
|
|
366
|
+
|
|
367
|
+
reply.send({ hello: 'world' })
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
await fastify.inject({
|
|
371
|
+
path: '/',
|
|
372
|
+
method: 'GET'
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
subtest.test(
|
|
378
|
+
'Should use the custom validator compiler for the route',
|
|
379
|
+
async t => {
|
|
380
|
+
const fastify = Fastify()
|
|
381
|
+
let called = 0
|
|
382
|
+
const custom = ({ schema, httpPart, url, method }) => {
|
|
383
|
+
t.equal(schema, defaultSchema)
|
|
384
|
+
t.equal(url, '/')
|
|
385
|
+
t.equal(method, 'GET')
|
|
386
|
+
t.equal(httpPart, 'querystring')
|
|
387
|
+
|
|
388
|
+
return input => {
|
|
389
|
+
called++
|
|
390
|
+
t.same(input, { hello: 'world' })
|
|
391
|
+
return true
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
t.plan(9)
|
|
396
|
+
|
|
397
|
+
fastify.get('/', { validatorCompiler: custom }, (req, reply) => {
|
|
398
|
+
const ok = req.validateInput(
|
|
399
|
+
{ hello: 'world' },
|
|
400
|
+
defaultSchema,
|
|
401
|
+
'querystring'
|
|
402
|
+
)
|
|
403
|
+
const ok2 = req.validateInput({ hello: 'world' }, defaultSchema)
|
|
404
|
+
|
|
405
|
+
t.ok(ok)
|
|
406
|
+
t.ok(ok2)
|
|
407
|
+
t.equal(called, 2)
|
|
408
|
+
|
|
409
|
+
reply.send({ hello: 'world' })
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
await fastify.inject({
|
|
413
|
+
path: '/',
|
|
414
|
+
method: 'GET'
|
|
415
|
+
})
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
subtest.test(
|
|
420
|
+
'Should return true/false if input valid - With Schema for Route defined',
|
|
421
|
+
async t => {
|
|
422
|
+
const fastify = Fastify()
|
|
423
|
+
|
|
424
|
+
t.plan(8)
|
|
425
|
+
|
|
426
|
+
fastify.post(
|
|
427
|
+
'/:id',
|
|
428
|
+
{
|
|
429
|
+
schema: requestSchema
|
|
430
|
+
},
|
|
431
|
+
(req, reply) => {
|
|
432
|
+
const { params } = req
|
|
433
|
+
|
|
434
|
+
switch (params.id) {
|
|
435
|
+
case 1:
|
|
436
|
+
t.ok(req.validateInput({ hello: 'world' }, 'body'))
|
|
437
|
+
t.notOk(req.validateInput({ hello: [], world: 'foo' }, 'body'))
|
|
438
|
+
break
|
|
439
|
+
case 2:
|
|
440
|
+
t.notOk(req.validateInput({ foo: 'something' }, 'querystring'))
|
|
441
|
+
t.ok(req.validateInput({ foo: 'bar' }, 'querystring'))
|
|
442
|
+
break
|
|
443
|
+
case 3:
|
|
444
|
+
t.notOk(req.validateInput({ 'x-foo': [] }, 'headers'))
|
|
445
|
+
t.ok(req.validateInput({ 'x-foo': 'something' }, 'headers'))
|
|
446
|
+
break
|
|
447
|
+
case 4:
|
|
448
|
+
t.ok(req.validateInput({ id: params.id }, 'params'))
|
|
449
|
+
t.notOk(req.validateInput({ id: 0 }, 'params'))
|
|
450
|
+
break
|
|
451
|
+
default:
|
|
452
|
+
t.fail('Invalid id')
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
reply.send({ hello: 'world' })
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
const promises = []
|
|
460
|
+
|
|
461
|
+
for (let i = 1; i < 5; i++) {
|
|
462
|
+
promises.push(
|
|
463
|
+
fastify.inject({
|
|
464
|
+
path: `/${i}`,
|
|
465
|
+
method: 'post',
|
|
466
|
+
query: { foo: 'bar' },
|
|
467
|
+
payload: {
|
|
468
|
+
hello: 'world'
|
|
469
|
+
},
|
|
470
|
+
headers: {
|
|
471
|
+
'x-foo': 'x-bar'
|
|
472
|
+
}
|
|
473
|
+
})
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
await Promise.all(promises)
|
|
478
|
+
}
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
subtest.test(
|
|
482
|
+
'Should throw if missing validation fn for HTTP part and not schema provided',
|
|
483
|
+
async t => {
|
|
484
|
+
const fastify = Fastify()
|
|
485
|
+
|
|
486
|
+
t.plan(10)
|
|
487
|
+
|
|
488
|
+
fastify.get('/:id', (req, reply) => {
|
|
489
|
+
const { params } = req
|
|
490
|
+
|
|
491
|
+
switch (parseInt(params.id)) {
|
|
492
|
+
case 1:
|
|
493
|
+
req.validateInput({}, 'body')
|
|
494
|
+
break
|
|
495
|
+
case 2:
|
|
496
|
+
req.validateInput({}, 'querystring')
|
|
497
|
+
break
|
|
498
|
+
case 3:
|
|
499
|
+
req.validateInput({}, 'query')
|
|
500
|
+
break
|
|
501
|
+
case 4:
|
|
502
|
+
req.validateInput({ 'x-foo': [] }, 'headers')
|
|
503
|
+
break
|
|
504
|
+
case 5:
|
|
505
|
+
req.validateInput({ id: 0 }, 'params')
|
|
506
|
+
break
|
|
507
|
+
default:
|
|
508
|
+
t.fail('Invalid id')
|
|
509
|
+
}
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
const promises = []
|
|
513
|
+
|
|
514
|
+
for (let i = 1; i < 6; i++) {
|
|
515
|
+
promises.push(
|
|
516
|
+
(async j => {
|
|
517
|
+
const response = await fastify.inject(`/${j}`)
|
|
518
|
+
|
|
519
|
+
const result = response.json()
|
|
520
|
+
t.equal(result.statusCode, 500)
|
|
521
|
+
t.equal(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')
|
|
522
|
+
})(i)
|
|
523
|
+
)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
await Promise.all(promises)
|
|
527
|
+
}
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
subtest.test(
|
|
531
|
+
'Should throw if missing validation fn for HTTP part and not valid schema provided',
|
|
532
|
+
async t => {
|
|
533
|
+
const fastify = Fastify()
|
|
534
|
+
|
|
535
|
+
t.plan(10)
|
|
536
|
+
|
|
537
|
+
fastify.get('/:id', (req, reply) => {
|
|
538
|
+
const { params } = req
|
|
539
|
+
|
|
540
|
+
switch (parseInt(params.id)) {
|
|
541
|
+
case 1:
|
|
542
|
+
req.validateInput({}, 1, 'body')
|
|
543
|
+
break
|
|
544
|
+
case 2:
|
|
545
|
+
req.validateInput({}, [], 'querystring')
|
|
546
|
+
break
|
|
547
|
+
case 3:
|
|
548
|
+
req.validateInput({}, '', 'query')
|
|
549
|
+
break
|
|
550
|
+
case 4:
|
|
551
|
+
req.validateInput({ 'x-foo': [] }, null, 'headers')
|
|
552
|
+
break
|
|
553
|
+
case 5:
|
|
554
|
+
req.validateInput({ id: 0 }, () => {}, 'params')
|
|
555
|
+
break
|
|
556
|
+
default:
|
|
557
|
+
t.fail('Invalid id')
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
const promises = []
|
|
562
|
+
|
|
563
|
+
for (let i = 1; i < 6; i++) {
|
|
564
|
+
promises.push(
|
|
565
|
+
(async j => {
|
|
566
|
+
const response = await fastify.inject({
|
|
567
|
+
path: `/${j}`,
|
|
568
|
+
method: 'GET'
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
const result = response.json()
|
|
572
|
+
t.equal(result.statusCode, 500)
|
|
573
|
+
t.equal(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')
|
|
574
|
+
})(i)
|
|
575
|
+
)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
await Promise.all(promises)
|
|
579
|
+
}
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
subtest.test('Should throw if invalid schema passed', async t => {
|
|
583
|
+
const fastify = Fastify()
|
|
584
|
+
|
|
585
|
+
t.plan(10)
|
|
586
|
+
|
|
587
|
+
fastify.get('/:id', (req, reply) => {
|
|
588
|
+
const { params } = req
|
|
589
|
+
|
|
590
|
+
switch (parseInt(params.id)) {
|
|
591
|
+
case 1:
|
|
592
|
+
req.validateInput({}, 1)
|
|
593
|
+
break
|
|
594
|
+
case 2:
|
|
595
|
+
req.validateInput({}, '')
|
|
596
|
+
break
|
|
597
|
+
case 3:
|
|
598
|
+
req.validateInput({}, [])
|
|
599
|
+
break
|
|
600
|
+
case 4:
|
|
601
|
+
req.validateInput({ 'x-foo': [] }, null)
|
|
602
|
+
break
|
|
603
|
+
case 5:
|
|
604
|
+
req.validateInput({ id: 0 }, () => {})
|
|
605
|
+
break
|
|
606
|
+
default:
|
|
607
|
+
t.fail('Invalid id')
|
|
608
|
+
}
|
|
609
|
+
})
|
|
610
|
+
|
|
611
|
+
const promises = []
|
|
612
|
+
|
|
613
|
+
for (let i = 1; i < 6; i++) {
|
|
614
|
+
promises.push(
|
|
615
|
+
(async j => {
|
|
616
|
+
const response = await fastify.inject({
|
|
617
|
+
path: `/${j}`,
|
|
618
|
+
method: 'GET'
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
const result = response.json()
|
|
622
|
+
t.equal(result.statusCode, 500)
|
|
623
|
+
t.equal(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')
|
|
624
|
+
})(i)
|
|
625
|
+
)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
await Promise.all(promises)
|
|
629
|
+
})
|
|
630
|
+
|
|
631
|
+
subtest.test(
|
|
632
|
+
'Should set a WeakMap if compiling the very first schema',
|
|
633
|
+
async t => {
|
|
634
|
+
const fastify = Fastify()
|
|
635
|
+
|
|
636
|
+
t.plan(3)
|
|
637
|
+
|
|
638
|
+
fastify.get('/', (req, reply) => {
|
|
639
|
+
t.equal(req.context[kRequestValidateWeakMap], null)
|
|
640
|
+
t.equal(req.validateInput({ hello: 'world' }, defaultSchema), true)
|
|
641
|
+
t.type(req.context[kRequestValidateWeakMap], WeakMap)
|
|
642
|
+
|
|
643
|
+
reply.send({ hello: 'world' })
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
await fastify.inject({
|
|
647
|
+
path: '/',
|
|
648
|
+
method: 'GET'
|
|
649
|
+
})
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
test('Nested Context', subtest => {
|
|
655
|
+
subtest.plan(1)
|
|
656
|
+
|
|
657
|
+
subtest.test('Level_1', tst => {
|
|
658
|
+
tst.plan(3)
|
|
659
|
+
tst.test('#compileValidationSchema', ntst => {
|
|
660
|
+
ntst.plan(4)
|
|
661
|
+
|
|
662
|
+
ntst.test('Should return a function - Route without schema', async t => {
|
|
663
|
+
const fastify = Fastify()
|
|
664
|
+
|
|
665
|
+
fastify.register((instance, opts, next) => {
|
|
666
|
+
instance.get('/', (req, reply) => {
|
|
667
|
+
const validate = req.compileValidationSchema(defaultSchema)
|
|
668
|
+
|
|
669
|
+
t.type(validate, Function)
|
|
670
|
+
t.ok(validate({ hello: 'world' }))
|
|
671
|
+
t.notOk(validate({ world: 'foo' }))
|
|
672
|
+
|
|
673
|
+
reply.send({ hello: 'world' })
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
next()
|
|
677
|
+
})
|
|
678
|
+
|
|
679
|
+
t.plan(3)
|
|
680
|
+
|
|
681
|
+
await fastify.inject({
|
|
682
|
+
path: '/',
|
|
683
|
+
method: 'GET'
|
|
684
|
+
})
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
ntst.test(
|
|
688
|
+
'Should reuse the validate fn across multiple invocations - Route without schema',
|
|
689
|
+
async t => {
|
|
690
|
+
const fastify = Fastify()
|
|
691
|
+
let validate = null
|
|
692
|
+
let counter = 0
|
|
693
|
+
|
|
694
|
+
t.plan(16)
|
|
695
|
+
|
|
696
|
+
fastify.register((instance, opts, next) => {
|
|
697
|
+
instance.get('/', (req, reply) => {
|
|
698
|
+
counter++
|
|
699
|
+
if (counter > 1) {
|
|
700
|
+
const newValidate = req.compileValidationSchema(defaultSchema)
|
|
701
|
+
t.equal(validate, newValidate, 'Are the same validate function')
|
|
702
|
+
validate = newValidate
|
|
703
|
+
} else {
|
|
704
|
+
validate = req.compileValidationSchema(defaultSchema)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
t.type(validate, Function)
|
|
708
|
+
t.ok(validate({ hello: 'world' }))
|
|
709
|
+
t.notOk(validate({ world: 'foo' }))
|
|
710
|
+
|
|
711
|
+
reply.send({ hello: 'world' })
|
|
712
|
+
})
|
|
713
|
+
|
|
714
|
+
next()
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
await Promise.all([
|
|
718
|
+
fastify.inject('/'),
|
|
719
|
+
fastify.inject('/'),
|
|
720
|
+
fastify.inject('/'),
|
|
721
|
+
fastify.inject('/')
|
|
722
|
+
])
|
|
723
|
+
|
|
724
|
+
t.equal(counter, 4)
|
|
725
|
+
}
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
ntst.test('Should return a function - Route with schema', async t => {
|
|
729
|
+
const fastify = Fastify()
|
|
730
|
+
|
|
731
|
+
t.plan(3)
|
|
732
|
+
|
|
733
|
+
fastify.register((instance, opts, next) => {
|
|
734
|
+
instance.post(
|
|
735
|
+
'/',
|
|
736
|
+
{
|
|
737
|
+
schema: {
|
|
738
|
+
body: defaultSchema
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
(req, reply) => {
|
|
742
|
+
const validate = req.compileValidationSchema(defaultSchema)
|
|
743
|
+
|
|
744
|
+
t.type(validate, Function)
|
|
745
|
+
t.ok(validate({ hello: 'world' }))
|
|
746
|
+
t.notOk(validate({ world: 'foo' }))
|
|
747
|
+
|
|
748
|
+
reply.send({ hello: 'world' })
|
|
749
|
+
}
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
next()
|
|
753
|
+
})
|
|
754
|
+
|
|
755
|
+
await fastify.inject({
|
|
756
|
+
path: '/',
|
|
757
|
+
method: 'POST',
|
|
758
|
+
payload: {
|
|
759
|
+
hello: 'world',
|
|
760
|
+
world: 'foo'
|
|
761
|
+
}
|
|
762
|
+
})
|
|
763
|
+
})
|
|
764
|
+
|
|
765
|
+
ntst.test(
|
|
766
|
+
'Should use the custom validator compiler for the route',
|
|
767
|
+
async t => {
|
|
768
|
+
const fastify = Fastify()
|
|
769
|
+
let called = 0
|
|
770
|
+
|
|
771
|
+
t.plan(10)
|
|
772
|
+
|
|
773
|
+
fastify.register((instance, opts, next) => {
|
|
774
|
+
const custom = ({ schema, httpPart, url, method }) => {
|
|
775
|
+
t.equal(schema, defaultSchema)
|
|
776
|
+
t.equal(url, '/')
|
|
777
|
+
t.equal(method, 'GET')
|
|
778
|
+
t.equal(httpPart, 'querystring')
|
|
779
|
+
|
|
780
|
+
return input => {
|
|
781
|
+
called++
|
|
782
|
+
t.same(input, { hello: 'world' })
|
|
783
|
+
return true
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
fastify.get('/', { validatorCompiler: custom }, (req, reply) => {
|
|
788
|
+
const first = req.compileValidationSchema(
|
|
789
|
+
defaultSchema,
|
|
790
|
+
'querystring'
|
|
791
|
+
)
|
|
792
|
+
const second = req.compileValidationSchema(
|
|
793
|
+
defaultSchema,
|
|
794
|
+
'querystring'
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
t.equal(first, second)
|
|
798
|
+
t.ok(first({ hello: 'world' }))
|
|
799
|
+
t.ok(second({ hello: 'world' }))
|
|
800
|
+
t.equal(called, 2)
|
|
801
|
+
|
|
802
|
+
reply.send({ hello: 'world' })
|
|
803
|
+
})
|
|
804
|
+
|
|
805
|
+
next()
|
|
806
|
+
})
|
|
807
|
+
|
|
808
|
+
await fastify.inject('/')
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
})
|
|
812
|
+
|
|
813
|
+
tst.test('#getValidationFunction', ntst => {
|
|
814
|
+
ntst.plan(6)
|
|
815
|
+
|
|
816
|
+
ntst.test('Should return a validation function', async t => {
|
|
817
|
+
const fastify = Fastify()
|
|
818
|
+
|
|
819
|
+
t.plan(1)
|
|
820
|
+
|
|
821
|
+
fastify.register((instance, opts, next) => {
|
|
822
|
+
instance.get('/', (req, reply) => {
|
|
823
|
+
const original = req.compileValidationSchema(defaultSchema)
|
|
824
|
+
const referenced = req.getValidationFunction(defaultSchema)
|
|
825
|
+
|
|
826
|
+
t.equal(original, referenced)
|
|
827
|
+
|
|
828
|
+
reply.send({ hello: 'world' })
|
|
829
|
+
})
|
|
830
|
+
|
|
831
|
+
next()
|
|
832
|
+
})
|
|
833
|
+
|
|
834
|
+
await fastify.inject('/')
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
ntst.test('Should return undefined if no schema compiled', async t => {
|
|
838
|
+
const fastify = Fastify()
|
|
839
|
+
|
|
840
|
+
t.plan(1)
|
|
841
|
+
|
|
842
|
+
fastify.register((instance, opts, next) => {
|
|
843
|
+
instance.get('/', (req, reply) => {
|
|
844
|
+
const validate = req.getValidationFunction(defaultSchema)
|
|
845
|
+
|
|
846
|
+
t.notOk(validate)
|
|
847
|
+
|
|
848
|
+
reply.send({ hello: 'world' })
|
|
849
|
+
})
|
|
850
|
+
|
|
851
|
+
next()
|
|
852
|
+
})
|
|
853
|
+
|
|
854
|
+
await fastify.inject('/')
|
|
855
|
+
})
|
|
856
|
+
|
|
857
|
+
ntst.test(
|
|
858
|
+
'Should return the validation function from each HTTP part',
|
|
859
|
+
async t => {
|
|
860
|
+
const fastify = Fastify()
|
|
861
|
+
let headerValidation = null
|
|
862
|
+
let customValidation = null
|
|
863
|
+
|
|
864
|
+
t.plan(15)
|
|
865
|
+
|
|
866
|
+
fastify.register((instance, opts, next) => {
|
|
867
|
+
instance.post(
|
|
868
|
+
'/:id',
|
|
869
|
+
{
|
|
870
|
+
schema: requestSchema
|
|
871
|
+
},
|
|
872
|
+
(req, reply) => {
|
|
873
|
+
const { params } = req
|
|
874
|
+
|
|
875
|
+
switch (params.id) {
|
|
876
|
+
case 1:
|
|
877
|
+
customValidation = req.compileValidationSchema(
|
|
878
|
+
defaultSchema
|
|
879
|
+
)
|
|
880
|
+
t.ok(req.getValidationFunction('body'))
|
|
881
|
+
t.ok(req.getValidationFunction('body')({ hello: 'world' }))
|
|
882
|
+
t.notOk(
|
|
883
|
+
req.getValidationFunction('body')({ world: 'hello' })
|
|
884
|
+
)
|
|
885
|
+
break
|
|
886
|
+
case 2:
|
|
887
|
+
headerValidation = req.getValidationFunction('headers')
|
|
888
|
+
t.ok(headerValidation)
|
|
889
|
+
t.ok(headerValidation({ 'x-foo': 'world' }))
|
|
890
|
+
t.notOk(headerValidation({ 'x-foo': [] }))
|
|
891
|
+
break
|
|
892
|
+
case 3:
|
|
893
|
+
t.ok(req.getValidationFunction('params'))
|
|
894
|
+
t.ok(req.getValidationFunction('params')({ id: 123 }))
|
|
895
|
+
t.notOk(req.getValidationFunction('params'({ id: 1.2 })))
|
|
896
|
+
break
|
|
897
|
+
case 4:
|
|
898
|
+
t.ok(req.getValidationFunction('querystring'))
|
|
899
|
+
t.ok(
|
|
900
|
+
req.getValidationFunction('querystring')({ foo: 'bar' })
|
|
901
|
+
)
|
|
902
|
+
t.notOk(
|
|
903
|
+
req.getValidationFunction('querystring')({
|
|
904
|
+
foo: 'not-bar'
|
|
905
|
+
})
|
|
906
|
+
)
|
|
907
|
+
break
|
|
908
|
+
case 5:
|
|
909
|
+
t.equal(
|
|
910
|
+
customValidation,
|
|
911
|
+
req.getValidationFunction(defaultSchema)
|
|
912
|
+
)
|
|
913
|
+
t.ok(customValidation({ hello: 'world' }))
|
|
914
|
+
t.notOk(customValidation({}))
|
|
915
|
+
t.equal(
|
|
916
|
+
headerValidation,
|
|
917
|
+
req.getValidationFunction('headers')
|
|
918
|
+
)
|
|
919
|
+
break
|
|
920
|
+
default:
|
|
921
|
+
t.fail('Invalid id')
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
reply.send({ hello: 'world' })
|
|
925
|
+
}
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
next()
|
|
929
|
+
})
|
|
930
|
+
const promises = []
|
|
931
|
+
|
|
932
|
+
for (let i = 1; i < 6; i++) {
|
|
933
|
+
promises.push(
|
|
934
|
+
fastify.inject({
|
|
935
|
+
path: `/${i}`,
|
|
936
|
+
method: 'post',
|
|
937
|
+
query: { foo: 'bar' },
|
|
938
|
+
payload: {
|
|
939
|
+
hello: 'world'
|
|
940
|
+
},
|
|
941
|
+
headers: {
|
|
942
|
+
'x-foo': 'x-bar'
|
|
943
|
+
}
|
|
944
|
+
})
|
|
945
|
+
)
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
await Promise.all(promises)
|
|
949
|
+
}
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
ntst.test('Should return a validation function - nested', async t => {
|
|
953
|
+
const fastify = Fastify()
|
|
954
|
+
let called = false
|
|
955
|
+
const custom = ({ schema, httpPart, url, method }) => {
|
|
956
|
+
t.equal(schema, defaultSchema)
|
|
957
|
+
t.equal(url, '/')
|
|
958
|
+
t.equal(method, 'GET')
|
|
959
|
+
t.notOk(httpPart)
|
|
960
|
+
|
|
961
|
+
called = true
|
|
962
|
+
return () => true
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
t.plan(6)
|
|
966
|
+
|
|
967
|
+
fastify.setValidatorCompiler(custom)
|
|
968
|
+
|
|
969
|
+
fastify.register((instance, opts, next) => {
|
|
970
|
+
instance.get('/', (req, reply) => {
|
|
971
|
+
const original = req.compileValidationSchema(defaultSchema)
|
|
972
|
+
const referenced = req.getValidationFunction(defaultSchema)
|
|
973
|
+
|
|
974
|
+
t.equal(original, referenced)
|
|
975
|
+
t.equal(called, true)
|
|
976
|
+
|
|
977
|
+
reply.send({ hello: 'world' })
|
|
978
|
+
})
|
|
979
|
+
|
|
980
|
+
next()
|
|
981
|
+
})
|
|
982
|
+
|
|
983
|
+
await fastify.inject('/')
|
|
984
|
+
})
|
|
985
|
+
|
|
986
|
+
ntst.test(
|
|
987
|
+
'Should return undefined if no schema compiled - nested',
|
|
988
|
+
async t => {
|
|
989
|
+
const fastify = Fastify()
|
|
990
|
+
let called = 0
|
|
991
|
+
const custom = ({ schema, httpPart, url, method }) => {
|
|
992
|
+
called++
|
|
993
|
+
return () => true
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
t.plan(3)
|
|
997
|
+
|
|
998
|
+
fastify.setValidatorCompiler(custom)
|
|
999
|
+
|
|
1000
|
+
fastify.get('/', (req, reply) => {
|
|
1001
|
+
const validate = req.compileValidationSchema(defaultSchema)
|
|
1002
|
+
|
|
1003
|
+
t.equal(typeof validate, 'function')
|
|
1004
|
+
|
|
1005
|
+
reply.send({ hello: 'world' })
|
|
1006
|
+
})
|
|
1007
|
+
|
|
1008
|
+
fastify.register(
|
|
1009
|
+
(instance, opts, next) => {
|
|
1010
|
+
instance.get('/', (req, reply) => {
|
|
1011
|
+
const validate = req.getValidationFunction(defaultSchema)
|
|
1012
|
+
|
|
1013
|
+
t.notOk(validate)
|
|
1014
|
+
t.equal(called, 1)
|
|
1015
|
+
|
|
1016
|
+
reply.send({ hello: 'world' })
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
next()
|
|
1020
|
+
},
|
|
1021
|
+
{ prefix: '/nested' }
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
await fastify.inject('/')
|
|
1025
|
+
await fastify.inject('/nested')
|
|
1026
|
+
}
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
ntst.test('Should per-route defined validation compiler', async t => {
|
|
1030
|
+
const fastify = Fastify()
|
|
1031
|
+
let validateParent
|
|
1032
|
+
let validateChild
|
|
1033
|
+
let calledParent = 0
|
|
1034
|
+
let calledChild = 0
|
|
1035
|
+
const customParent = ({ schema, httpPart, url, method }) => {
|
|
1036
|
+
calledParent++
|
|
1037
|
+
return () => true
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const customChild = ({ schema, httpPart, url, method }) => {
|
|
1041
|
+
calledChild++
|
|
1042
|
+
return () => true
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
t.plan(5)
|
|
1046
|
+
|
|
1047
|
+
fastify.setValidatorCompiler(customParent)
|
|
1048
|
+
|
|
1049
|
+
fastify.get('/', (req, reply) => {
|
|
1050
|
+
validateParent = req.compileValidationSchema(defaultSchema)
|
|
1051
|
+
|
|
1052
|
+
t.equal(typeof validateParent, 'function')
|
|
1053
|
+
|
|
1054
|
+
reply.send({ hello: 'world' })
|
|
1055
|
+
})
|
|
1056
|
+
|
|
1057
|
+
fastify.register(
|
|
1058
|
+
(instance, opts, next) => {
|
|
1059
|
+
instance.get(
|
|
1060
|
+
'/',
|
|
1061
|
+
{
|
|
1062
|
+
validatorCompiler: customChild
|
|
1063
|
+
},
|
|
1064
|
+
(req, reply) => {
|
|
1065
|
+
const validate1 = req.compileValidationSchema(defaultSchema)
|
|
1066
|
+
validateChild = req.getValidationFunction(defaultSchema)
|
|
1067
|
+
|
|
1068
|
+
t.equal(validate1, validateChild)
|
|
1069
|
+
t.not(validateParent, validateChild)
|
|
1070
|
+
t.equal(calledParent, 1)
|
|
1071
|
+
t.equal(calledChild, 1)
|
|
1072
|
+
|
|
1073
|
+
reply.send({ hello: 'world' })
|
|
1074
|
+
}
|
|
1075
|
+
)
|
|
1076
|
+
|
|
1077
|
+
next()
|
|
1078
|
+
},
|
|
1079
|
+
{ prefix: '/nested' }
|
|
1080
|
+
)
|
|
1081
|
+
|
|
1082
|
+
await fastify.inject('/')
|
|
1083
|
+
await fastify.inject('/nested')
|
|
1084
|
+
})
|
|
1085
|
+
})
|
|
1086
|
+
|
|
1087
|
+
tst.test('#validate', ntst => {
|
|
1088
|
+
ntst.plan(3)
|
|
1089
|
+
|
|
1090
|
+
ntst.test(
|
|
1091
|
+
'Should return true/false if input valid - Route without schema',
|
|
1092
|
+
async t => {
|
|
1093
|
+
const fastify = Fastify()
|
|
1094
|
+
|
|
1095
|
+
t.plan(2)
|
|
1096
|
+
|
|
1097
|
+
fastify.register((instance, opts, next) => {
|
|
1098
|
+
instance.get('/', (req, reply) => {
|
|
1099
|
+
const isNotValid = req.validateInput(
|
|
1100
|
+
{ world: 'string' },
|
|
1101
|
+
defaultSchema
|
|
1102
|
+
)
|
|
1103
|
+
const isValid = req.validateInput({ hello: 'string' }, defaultSchema)
|
|
1104
|
+
|
|
1105
|
+
t.notOk(isNotValid)
|
|
1106
|
+
t.ok(isValid)
|
|
1107
|
+
|
|
1108
|
+
reply.send({ hello: 'world' })
|
|
1109
|
+
})
|
|
1110
|
+
|
|
1111
|
+
next()
|
|
1112
|
+
})
|
|
1113
|
+
|
|
1114
|
+
await fastify.inject('/')
|
|
1115
|
+
}
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1118
|
+
ntst.test(
|
|
1119
|
+
'Should use the custom validator compiler for the route',
|
|
1120
|
+
async t => {
|
|
1121
|
+
const fastify = Fastify()
|
|
1122
|
+
let parentCalled = 0
|
|
1123
|
+
let childCalled = 0
|
|
1124
|
+
const customParent = () => {
|
|
1125
|
+
parentCalled++
|
|
1126
|
+
|
|
1127
|
+
return () => true
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const customChild = ({ schema, httpPart, url, method }) => {
|
|
1131
|
+
t.equal(schema, defaultSchema)
|
|
1132
|
+
t.equal(url, '/')
|
|
1133
|
+
t.equal(method, 'GET')
|
|
1134
|
+
t.equal(httpPart, 'querystring')
|
|
1135
|
+
|
|
1136
|
+
return input => {
|
|
1137
|
+
childCalled++
|
|
1138
|
+
t.same(input, { hello: 'world' })
|
|
1139
|
+
return true
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
t.plan(10)
|
|
1144
|
+
|
|
1145
|
+
fastify.setValidatorCompiler(customParent)
|
|
1146
|
+
|
|
1147
|
+
fastify.register((instance, opts, next) => {
|
|
1148
|
+
instance.get(
|
|
1149
|
+
'/',
|
|
1150
|
+
{ validatorCompiler: customChild },
|
|
1151
|
+
(req, reply) => {
|
|
1152
|
+
const ok = req.validateInput(
|
|
1153
|
+
{ hello: 'world' },
|
|
1154
|
+
defaultSchema,
|
|
1155
|
+
'querystring'
|
|
1156
|
+
)
|
|
1157
|
+
const ok2 = req.validateInput({ hello: 'world' }, defaultSchema)
|
|
1158
|
+
|
|
1159
|
+
t.ok(ok)
|
|
1160
|
+
t.ok(ok2)
|
|
1161
|
+
t.equal(childCalled, 2)
|
|
1162
|
+
t.equal(parentCalled, 0)
|
|
1163
|
+
|
|
1164
|
+
reply.send({ hello: 'world' })
|
|
1165
|
+
}
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
next()
|
|
1169
|
+
})
|
|
1170
|
+
|
|
1171
|
+
await fastify.inject('/')
|
|
1172
|
+
}
|
|
1173
|
+
)
|
|
1174
|
+
|
|
1175
|
+
ntst.test(
|
|
1176
|
+
'Should return true/false if input valid - With Schema for Route defined and scoped validator compiler',
|
|
1177
|
+
async t => {
|
|
1178
|
+
const validator = new Ajv()
|
|
1179
|
+
const fastify = Fastify()
|
|
1180
|
+
const childCounter = {
|
|
1181
|
+
query: 0,
|
|
1182
|
+
body: 0,
|
|
1183
|
+
params: 0,
|
|
1184
|
+
headers: 0
|
|
1185
|
+
}
|
|
1186
|
+
let parentCalled = 0
|
|
1187
|
+
|
|
1188
|
+
const parent = () => {
|
|
1189
|
+
parentCalled++
|
|
1190
|
+
return () => true
|
|
1191
|
+
}
|
|
1192
|
+
const child = ({ schema, httpPart, url, method }) => {
|
|
1193
|
+
httpPart = httpPart === 'querystring' ? 'query' : httpPart
|
|
1194
|
+
const validate = validator.compile(schema)
|
|
1195
|
+
|
|
1196
|
+
return input => {
|
|
1197
|
+
childCounter[httpPart]++
|
|
1198
|
+
return validate(input)
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
t.plan(13)
|
|
1203
|
+
|
|
1204
|
+
fastify.setValidatorCompiler(parent)
|
|
1205
|
+
fastify.register((instance, opts, next) => {
|
|
1206
|
+
instance.setValidatorCompiler(child)
|
|
1207
|
+
instance.post(
|
|
1208
|
+
'/:id',
|
|
1209
|
+
{
|
|
1210
|
+
schema: requestSchema
|
|
1211
|
+
},
|
|
1212
|
+
(req, reply) => {
|
|
1213
|
+
const { params } = req
|
|
1214
|
+
|
|
1215
|
+
switch (parseInt(params.id)) {
|
|
1216
|
+
case 1:
|
|
1217
|
+
t.ok(req.validateInput({ hello: 'world' }, 'body'))
|
|
1218
|
+
t.notOk(req.validateInput({ hello: [], world: 'foo' }, 'body'))
|
|
1219
|
+
break
|
|
1220
|
+
case 2:
|
|
1221
|
+
t.notOk(req.validateInput({ foo: 'something' }, 'querystring'))
|
|
1222
|
+
t.ok(req.validateInput({ foo: 'bar' }, 'querystring'))
|
|
1223
|
+
break
|
|
1224
|
+
case 3:
|
|
1225
|
+
t.notOk(req.validateInput({ 'x-foo': [] }, 'headers'))
|
|
1226
|
+
t.ok(req.validateInput({ 'x-foo': 'something' }, 'headers'))
|
|
1227
|
+
break
|
|
1228
|
+
case 4:
|
|
1229
|
+
t.ok(req.validateInput({ id: 1 }, 'params'))
|
|
1230
|
+
t.notOk(req.validateInput({ id: params.id }, 'params'))
|
|
1231
|
+
break
|
|
1232
|
+
default:
|
|
1233
|
+
t.fail('Invalid id')
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
reply.send({ hello: 'world' })
|
|
1237
|
+
}
|
|
1238
|
+
)
|
|
1239
|
+
|
|
1240
|
+
next()
|
|
1241
|
+
})
|
|
1242
|
+
|
|
1243
|
+
const promises = []
|
|
1244
|
+
|
|
1245
|
+
for (let i = 1; i < 5; i++) {
|
|
1246
|
+
promises.push(
|
|
1247
|
+
fastify.inject({
|
|
1248
|
+
path: `/${i}`,
|
|
1249
|
+
method: 'post',
|
|
1250
|
+
query: {},
|
|
1251
|
+
payload: {
|
|
1252
|
+
hello: 'world'
|
|
1253
|
+
}
|
|
1254
|
+
})
|
|
1255
|
+
)
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
await Promise.all(promises)
|
|
1259
|
+
|
|
1260
|
+
t.equal(childCounter.query, 6) // 4 calls made + 2 custom validations
|
|
1261
|
+
t.equal(childCounter.headers, 6) // 4 calls made + 2 custom validations
|
|
1262
|
+
t.equal(childCounter.body, 6) // 4 calls made + 2 custom validations
|
|
1263
|
+
t.equal(childCounter.params, 6) // 4 calls made + 2 custom validations
|
|
1264
|
+
t.equal(parentCalled, 0)
|
|
1265
|
+
}
|
|
1266
|
+
)
|
|
1267
|
+
})
|
|
1268
|
+
})
|
|
1269
|
+
})
|