Joi验证两个数组不可同时为空的实现问题求助
解决Joi中两个数组不能同时为空的验证问题
你遇到的循环依赖问题是因为使用when规则互相引用两个字段导致的,Joi不允许这种双向依赖。下面提供两种可行的解决方案,都能实现“addUsers和removeUsers不可同时为空或null”的需求:
方案一:使用自定义验证函数
这种方式最直观,直接在对象级别做整体校验,完全避免依赖问题:
const schema = Joi.object({ addUsers: Joi.array().items(Joi.string().email()).allow(null), removeUsers: Joi.array().items(Joi.string().email()).allow(null) }).custom((value, helpers) => { // 判断两个字段是否为空(null或空数组) const isAddEmpty = !value.addUsers || value.addUsers.length === 0; const isRemoveEmpty = !value.removeUsers || value.removeUsers.length === 0; if (isAddEmpty && isRemoveEmpty) { return helpers.error('any.invalid', { message: 'addUsers和removeUsers不能同时为空或null,至少要有一个数组包含邮箱地址' }); } return value; }).messages({ 'any.invalid': '{{#message}}' });
原理
通过custom方法添加自定义校验逻辑,直接检查两个字段的状态:如果两者都为空(null或空数组),则抛出错误;否则通过校验。这种方式完全脱离字段间的互相引用,不会产生循环依赖。
方案二:使用内置or规则组合子Schema
利用Joi的or规则,指定至少满足其中一个子Schema的条件,同样能避免循环依赖:
const schema = Joi.object({ addUsers: Joi.array().items(Joi.string().email()).allow(null), removeUsers: Joi.array().items(Joi.string().email()).allow(null) }).or( // 子Schema1:addUsers是长度≥1的数组 Joi.object({ addUsers: Joi.array().min(1) }), // 子Schema2:removeUsers是长度≥1的数组 Joi.object({ removeUsers: Joi.array().min(1) }) ).messages({ 'object.missing': 'addUsers和removeUsers不能同时为空或null,至少要有一个数组包含邮箱地址' });
原理
or规则要求对象至少满足其中一个传入的子Schema:要么addUsers是有元素的数组,要么removeUsers是有元素的数组。这种方式用内置规则组合实现需求,无需自定义函数,代码更简洁。
两种方案都支持以下合法场景:
- addUsers非空,removeUsers为空或null
- removeUsers非空,addUsers为空或null
- 两个数组都非空
同时会拒绝以下非法场景:
- addUsers和removeUsers都是null
- addUsers和removeUsers都是空数组
- 其中一个是null,另一个是空数组
内容的提问来源于stack exchange,提问作者thxmike
相关产品推荐
相关产品推荐

