javascript - 如何使用 Joi 验证具有相同模式但没有限制的嵌套对象
问题描述
假设我在下面的这种模式中有一个嵌套对象,我想用它来验证它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');
有人可以建议我正确的方法吗?
谢谢
解决方案
Both of your attempts are a great start but as you've found it's the recursive nature of the pattern that's tricky to deal with.
Thankfully Joi has a solution to this with .link()
:
Links to another schema node and reuses it for validation, typically for creative recursive schemas...
We can also make use of .pattern()
to avoid having to duplicate our rules for AND
and OR
.
I've found the following schema works:
// 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')
With test data:
{
"AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{
"OR": [
{ "key": "", "value": "" },
{ "key": "", "value": "" },
{
"AND": [
{ "key": "", "value": "" },
{ "key": "", "value": "" }
]
}
]
}
]
}
You can test it out here.
--
For those using a Joi version < v16 that doesn't support link()
, you can use lazy()
instead.
const schema = Joi.alternatives([
Joi.object().pattern(/^(AND|OR)$/, Joi.array().items(Joi.lazy(() => schema))),
Joi.object().keys({
key: Joi.string(),
value: Joi.string()
})
]);
推荐阅读
- c# - ASP.NET Core Identity,如何覆盖 IdentityRole Name 唯一索引?我想存储关于租户的重复名称
- web-scraping - 基于页面内容的操作
- javascript - 为什么我的选择器无法读取“状态”?状态未定义
- c# - 将列表项从任务添加到组合框
- performance - Apache Kafka 的 TPL 性能
- loops - 如何提高循环中的运行时间?
- angular - DOM7011:此页面上的代码禁用了前后缓存
- python - 如何使用 glumpy 放大/缩小 3D 图像?
- jquery - 仅当从下拉列表中选择选项时才附加到 iframe src
- c# - 在 c# 中使用具有父类型的子构造函数时会发生什么?父 x = new Child();