假设我在下面的模式中有一个嵌套对象,我想用Joi
验证它
{
"AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{ "OR": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{ "AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
...
]
},
...
],
...
]
}
这是我的V.1,它只允许1级深度:
const obj = Joi.object().keys({
key: Joi.string(),
value: Joi.string(),
});
obj.keys({
AND: Joi.array().items(obj),
OR: Joi.array().items(obj),
}).nand('AND', 'OR');
const nested = Joi.object()
.keys({
AND: Joi.array().items(obj),
OR: Joi.array().items(obj),
})
.nand('AND', 'OR');
这里的V.2只允许2级深度:
const obj = Joi.object().keys({
key: Joi.string(),
value: Joi.string(),
AND: Joi.array().items(Joi.object({ key: Joi.string(), value: Joi.string() })),
OR: Joi.array().items(Joi.object({ key: Joi.string(), value: Joi.string() })),
});
const nested = Joi.object()
.keys({
AND: Joi.array().items(obj),
OR: Joi.array().items(obj),
})
.nand('AND', 'OR');
有人能给我推荐正确的方法吗?
谢谢
您的两次尝试都是一个很好的开始,但正如您所发现的,模式的递归性质很难处理。
值得庆幸的是,Joi用.link()
:解决了这个问题
链接到另一个模式节点并重用它进行验证,通常用于创造性递归模式。。。
我们还可以使用.pattern()
来避免重复AND
和OR
的规则。
我发现以下模式有效:
// attempt to match one of these schemas
Joi.alternatives([
// an object containing the key AND or OR where it's value matches
// this entire schema definition
Joi.object().pattern(/^(AND|OR)$/, Joi.array().items(Joi.link('#schema'))),
// an object containing a key/value pair
Joi.object().keys({
key: Joi.string(),
value: Joi.string()
})
// we identify our schema with an ID so we can reference it in Joi.link()
]).id('schema')
带测试数据:
{
"AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{
"OR": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{
"AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" }
]
}
]
}
]
}
你可以在这里测试一下。
--
对于那些使用Joi版本<v16不支持link()
,您可以使用lazy()
。
const schema = Joi.alternatives([
Joi.object().pattern(/^(AND|OR)$/, Joi.array().items(Joi.lazy(() => schema))),
Joi.object().keys({
key: Joi.string(),
value: Joi.string()
})
]);