You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HapiJS/Joi:字段为字符串或指定键对象的验证及when报错问题

解决Joi验证title字段时的自引用when规则报错问题

你碰到的AssertionError [ERR_ASSERTION]: Item cannot come after itself: title(title)报错,本质是因为Joi不允许在when规则里直接引用同一个字段作为判断条件,这会触发自引用的循环依赖检测,导致验证失败。

针对你的需求(title既可以是必填字符串,也可以是包含指定语言键的必填对象),这里有两种靠谱的解决方式:

方法1:用alternatives实现(推荐)

这种方式最贴合你的需求场景,代码也更直观易懂,完全避开自引用问题:

const schema = Joi.object({
  title: Joi.alternatives()
    .try(
      // 第一种情况:必填字符串
      Joi.string().required(),
      // 第二种情况:必填对象,其中en_US必填,lt_LT可选
      Joi.object({
        en_US: Joi.string().required(),
        lt_LT: Joi.string()
      }).required()
    ).required()
});

alternatives().try()会依次尝试匹配传入的规则,只要满足其中任意一种格式,验证就会通过,完美适配你的业务场景。

方法2:修正when规则(避免自引用)

如果你一定要用when语法,可以通过引用当前对象的方式绕过自引用检测,不过这种写法不如第一种直观:

const schema = Joi.object({
  title: Joi.any()
    .when(Joi.in('$'), {
      // 判断当前对象的title是否为字符串类型
      is: Joi.object({ title: Joi.string() }),
      then: Joi.string().required(),
      otherwise: Joi.object({
        en_US: Joi.string().required(),
        lt_LT: Joi.string()
      }).required()
    }).required()
});

测试验证

你可以用这几个案例验证效果:

  • 字符串格式:schema.validate({ title: 'Chicken' }) → 验证通过
  • 多语言对象格式:schema.validate({ title: { en_US: 'Chicken', lt_LT: 'Vištiena' } }) → 验证通过
  • 缺失必填语言键:schema.validate({ title: { lt_LT: 'Vištiena' } }) → 因en_US缺失,验证失败

内容的提问来源于stack exchange,提问作者Combustible Pizza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:29