Joi 验证 - 如何要求或可选字段基于数组中存在的另一个键?
Joi validation - how to require or optional field based on another key exists in array?
我有这个 Joi 架构:
let schema = {};
let stations = {
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: {
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').required().error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
},
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
};
schema.stations = Joi.array().items(stations).min(1).max(5).required().error(JoiCustomErrors);
如您所见,schema.stations
是一个包含最少 1 个和最多 5 个元素的数组。
我希望每个元素只有在 "contact.first_name" AND "contact.last_name" AND "contact.phone"
存在(或根据架构正确填充)时才具有 "address.place" 字段。
我该怎么做?
您可以使用 Joi.when()
方法并创建如下模式:
Joi.object().keys({
contact: Joi.object().keys({
first_name: Joi.string(),
last_name: Joi.string(),
phone: Joi.string(),
}),
address: Joi.object().keys({
place: Joi.string(),
city: Joi.string().min(2).max(30),
street: Joi.string(),
house_number: Joi.string()
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.exist(),
last_name: Joi.exist(),
phone: Joi.exist(),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({ place: Joi.forbidden() })
}),
passengers_amount: Joi.number(),
notes: Joi.string()
});
我只是简化了您的架构,以便于理解。
基本上,我们这里说的是,如果contact.first_name,contact.last_name和contact.phone 存在,然后地址和address.place 是 必需的 ,否则 address.place 是 禁止的 .
例如,这个对象将失败,因为地址不存在:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
}
}
这将失败,因为 address.place 不存在:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
}
}
最后,根据定义的schema,这个对象会通过:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
place: 'd'
}
};
感谢 Soltex,这是应该使用的正确模式(但请参考我所做的更改):
Joi.object().keys({
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: Joi.object().keys({
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.string().min(1),
last_name: Joi.string().min(1),
phone: Joi.string().min(1),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({
place: Joi.optional().allow("")
})
}),
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
})
请注意,我的回答与 Soltex 的回答不同:
他将 "contact.first_name" "contact.last_name" "contact.phone" 设为:Joi.exists()。这不好,因为在这种情况下,即使是空对象也是 "exists",然后要求用户提供 "address.place"。我们不想要这样的东西,我们需要在每个字段中至少有一个字符。
此外,Soltex 答案中的 otherwise 语句使用 Joi.forbidden(),而这不是此处所需的行为 - 我们仍然需要允许用户提供位置,即使没有联系人,但这不应该是强制性的 - 所以我使用了:Joi.optional() .
我有这个 Joi 架构:
let schema = {};
let stations = {
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: {
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').required().error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
},
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
};
schema.stations = Joi.array().items(stations).min(1).max(5).required().error(JoiCustomErrors);
如您所见,schema.stations
是一个包含最少 1 个和最多 5 个元素的数组。
我希望每个元素只有在 "contact.first_name" AND "contact.last_name" AND "contact.phone"
存在(或根据架构正确填充)时才具有 "address.place" 字段。
我该怎么做?
您可以使用 Joi.when()
方法并创建如下模式:
Joi.object().keys({
contact: Joi.object().keys({
first_name: Joi.string(),
last_name: Joi.string(),
phone: Joi.string(),
}),
address: Joi.object().keys({
place: Joi.string(),
city: Joi.string().min(2).max(30),
street: Joi.string(),
house_number: Joi.string()
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.exist(),
last_name: Joi.exist(),
phone: Joi.exist(),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({ place: Joi.forbidden() })
}),
passengers_amount: Joi.number(),
notes: Joi.string()
});
我只是简化了您的架构,以便于理解。
基本上,我们这里说的是,如果contact.first_name,contact.last_name和contact.phone 存在,然后地址和address.place 是 必需的 ,否则 address.place 是 禁止的 .
例如,这个对象将失败,因为地址不存在:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
}
}
这将失败,因为 address.place 不存在:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
}
}
最后,根据定义的schema,这个对象会通过:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
place: 'd'
}
};
感谢 Soltex,这是应该使用的正确模式(但请参考我所做的更改):
Joi.object().keys({
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: Joi.object().keys({
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.string().min(1),
last_name: Joi.string().min(1),
phone: Joi.string().min(1),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({
place: Joi.optional().allow("")
})
}),
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
})
请注意,我的回答与 Soltex 的回答不同: 他将 "contact.first_name" "contact.last_name" "contact.phone" 设为:Joi.exists()。这不好,因为在这种情况下,即使是空对象也是 "exists",然后要求用户提供 "address.place"。我们不想要这样的东西,我们需要在每个字段中至少有一个字符。
此外,Soltex 答案中的 otherwise 语句使用 Joi.forbidden(),而这不是此处所需的行为 - 我们仍然需要允许用户提供位置,即使没有联系人,但这不应该是强制性的 - 所以我使用了:Joi.optional() .