将请求主体与整个请求分开验证
Validate request body separately from request as a whole
我有一个关于验证 PUT 请求的问题。请求的主体是一个对象数组。如果主体包含长度至少为 1 的数组,我希望请求成功,但我还需要对数组中的每个对象进行单独的验证,并将其传回响应中。所以我的 put body 是:
[1, 2, {id: "thirdObject"}]
即使前两项甚至不是对象,响应也应为 200。如果在正文中传递长度为 1 的数组,则请求只需要成功。响应需要类似于:
[{id: firstObject, status: 400, error: should be object}, {id: secondObject, status: 400, error: should be object}, { id: thirdObject, status: 204 }]
目前我正在使用流畅的模式验证正文:
body: S.array().items(myObjectSchema)
.minItems(1)
如果正文中的任何项目与 myObjectSchema 不匹配,这将导致 400。想知道您是否知道如何实现这一目标?
我不知道您使用的架构语法,但使用 JSON 架构的草案 7(https://json-schema.org/specification-links.html, and see also https://json-schema.org/understanding-json-schema 供参考 material),您可以:
{
"type": "array",
"minItems": 1
}
如果您想确保至少一个,但不一定所有项与您的对象类型匹配,则添加"contains" 关键词:
{
...,
"contains": ... reference to your object schema here
}
验证不会告诉您架构是否成功(例如{ id: thirdObject, status: 204 }
),因此您需要自行管理它。
为此,您需要创建一个错误处理程序来读取验证错误并与请求正文合并:
const fastify = require('fastify')()
const S = require('fluent-schema')
fastify.put('/', {
handler: () => { /** this will never executed if the schema validation fail */ },
schema: {
body: S.array().items(S.object()).minItems(1)
}
})
const errorHandler = (error, request, reply) => {
const { validation, validationContext } = error
// check if we have a validation error
if (validation) {
// here the validation error
console.log(validation)
// here the body
console.log(request.body)
reply.send(validation)
} else {
reply.send(error)
}
}
fastify.setErrorHandler(errorHandler)
fastify.inject({
method: 'PUT',
url: '/',
payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
console.log(res.json())
})
这将记录:
[
{
keyword: 'type',
dataPath: '[0]',
schemaPath: '#/items/type',
params: { type: 'object' },
message: 'should be object'
},
{
keyword: 'type',
dataPath: '[1]',
schemaPath: '#/items/type',
params: { type: 'object' },
message: 'should be object'
}
]
[ 1, 2, { id: 'thirdObject' } ]
如您所见,感谢 validation[].dataPath
,您能够了解正文数组的哪些元素无效并将数据合并到 return 您的信息。
考虑到在这种情况下不会执行处理程序。如果无论验证如何都需要执行它,则应该在 preHandler
挂钩中执行验证作业并避免默认模式验证检查(因为它是阻塞的)
编辑
const fastify = require('fastify')()
const S = require('fluent-schema')
let bodyValidator
fastify.decorateRequest('hasError', function () {
if (!bodyValidator) {
bodyValidator = fastify.schemaCompiler(S.array().items(S.object()).minItems(1).valueOf())
}
const valid = bodyValidator(this.body)
if (!valid) {
return bodyValidator.errors
}
return true
})
fastify.addHook('preHandler', (request, reply, done) => {
const errors = request.hasError()
if (errors) {
console.log(errors)
// show the same errors as before
// you can merge here or set request.errors = errors to let the handler read them
reply.send('here merge errors and request.body')
return
}
done() // needed to continue if you don't reply.send
})
fastify.put('/', { schema: { body: S.array() } }, (req, reply) => {
console.log('handler')
reply.send('handler')
})
fastify.inject({
method: 'PUT',
url: '/',
payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
console.log(res.json())
})
我有一个关于验证 PUT 请求的问题。请求的主体是一个对象数组。如果主体包含长度至少为 1 的数组,我希望请求成功,但我还需要对数组中的每个对象进行单独的验证,并将其传回响应中。所以我的 put body 是:
[1, 2, {id: "thirdObject"}]
即使前两项甚至不是对象,响应也应为 200。如果在正文中传递长度为 1 的数组,则请求只需要成功。响应需要类似于:
[{id: firstObject, status: 400, error: should be object}, {id: secondObject, status: 400, error: should be object}, { id: thirdObject, status: 204 }]
目前我正在使用流畅的模式验证正文:
body: S.array().items(myObjectSchema) .minItems(1)
如果正文中的任何项目与 myObjectSchema 不匹配,这将导致 400。想知道您是否知道如何实现这一目标?
我不知道您使用的架构语法,但使用 JSON 架构的草案 7(https://json-schema.org/specification-links.html, and see also https://json-schema.org/understanding-json-schema 供参考 material),您可以:
{
"type": "array",
"minItems": 1
}
如果您想确保至少一个,但不一定所有项与您的对象类型匹配,则添加"contains" 关键词:
{
...,
"contains": ... reference to your object schema here
}
验证不会告诉您架构是否成功(例如{ id: thirdObject, status: 204 }
),因此您需要自行管理它。
为此,您需要创建一个错误处理程序来读取验证错误并与请求正文合并:
const fastify = require('fastify')()
const S = require('fluent-schema')
fastify.put('/', {
handler: () => { /** this will never executed if the schema validation fail */ },
schema: {
body: S.array().items(S.object()).minItems(1)
}
})
const errorHandler = (error, request, reply) => {
const { validation, validationContext } = error
// check if we have a validation error
if (validation) {
// here the validation error
console.log(validation)
// here the body
console.log(request.body)
reply.send(validation)
} else {
reply.send(error)
}
}
fastify.setErrorHandler(errorHandler)
fastify.inject({
method: 'PUT',
url: '/',
payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
console.log(res.json())
})
这将记录:
[
{
keyword: 'type',
dataPath: '[0]',
schemaPath: '#/items/type',
params: { type: 'object' },
message: 'should be object'
},
{
keyword: 'type',
dataPath: '[1]',
schemaPath: '#/items/type',
params: { type: 'object' },
message: 'should be object'
}
]
[ 1, 2, { id: 'thirdObject' } ]
如您所见,感谢 validation[].dataPath
,您能够了解正文数组的哪些元素无效并将数据合并到 return 您的信息。
考虑到在这种情况下不会执行处理程序。如果无论验证如何都需要执行它,则应该在 preHandler
挂钩中执行验证作业并避免默认模式验证检查(因为它是阻塞的)
编辑
const fastify = require('fastify')()
const S = require('fluent-schema')
let bodyValidator
fastify.decorateRequest('hasError', function () {
if (!bodyValidator) {
bodyValidator = fastify.schemaCompiler(S.array().items(S.object()).minItems(1).valueOf())
}
const valid = bodyValidator(this.body)
if (!valid) {
return bodyValidator.errors
}
return true
})
fastify.addHook('preHandler', (request, reply, done) => {
const errors = request.hasError()
if (errors) {
console.log(errors)
// show the same errors as before
// you can merge here or set request.errors = errors to let the handler read them
reply.send('here merge errors and request.body')
return
}
done() // needed to continue if you don't reply.send
})
fastify.put('/', { schema: { body: S.array() } }, (req, reply) => {
console.log('handler')
reply.send('handler')
})
fastify.inject({
method: 'PUT',
url: '/',
payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
console.log(res.json())
})