Joi嵌套的“ when”条件在架构定义中失败,并显示“ ERR_ASSERTION”错误

问题描述

我一直在尝试与Joi(旧版本14.3.1)一起创建架构,但不幸的是,我被困住了。我尝试了多种定义模式的方法,但是结果总是伴随着模式定义错误

这是我的架构定义:

 const allowedUser = {
    admin: 'ADMIN',normal: 'norMAL'
  };

  const schema = validator
    .object()
    .keys({
      user: validator.any().valid(Object.values(allowedUser)).required(),context: validator.object().default({})
    })
    .when('user',{
      is: allowedUser.admin,then: validator.when(validator.object({ context: validator.exist() }),{
        then: validator.object().keys({
          session: validator.string().required()
        })
      })
    })
    .when('user',{
      is: allowedUser.normal,{
        then: validator.object().keys({
          id: validator.string().required()
        })
      })
    });

我尝试过的另一个模式定义:

  const schema = validator.object().keys({
    user: validator.any().valid(Object.values(allowedUser)).required(),context: validator
      .object()
      .when('user',{
        is: allowedUser.admin,then: validator.when('context',{
          is: validator.exist(),then: validator.object().keys({
            session: validator.string().required()
          })
        })
      })
      .when('user',{
        is: allowedUser.normal,then: validator.object().keys({
            id: validator.string().required()
          })
        })
      })
      .default({})
  });

所以架构的条件如下:

  1. 对于user,类型为ADMIN:如果定义了context属性,则它应包含属性session。如果context属性未定义,则应将认设置为{}
  2. 对于user,类型为norMAL:如果定义了context属性,则它应包含属性id。如果context属性未定义,则应将值认设置为{}
  3. 最明显的情况是,如果context属性包含未知属性,它也会失败

运行代码时,总是在模式定义中出现如下错误

AssertionError [ERR_ASSERTION]: Cannot merge type object with another type: alternatives
    

我的最小示例代码如下:

const validator = require('joi');


  const allowedUser = {
    admin: 'ADMIN',normal: 'norMAL'
  };

  const bodyWhenUndefined = {
    user: 'ADMIN',message: 'Hi'
  };

  const bodyWhenValidDefined = {
    user: 'ADMIN',message: 'Hi'
  };


  const bodyWhenDefinedEmpty = {
    user: 'ADMIN',message: 'Hi 2',context: {}
  };

  const bodyWhenDefinedWrong = {
    user: 'admin',message: 'Hi 3',context: {abc: 'wrong property'}
  };

  const schema = validator
    .object()
    .keys({
      user: validator.any().valid(Object.values(allowedUser)).required(),{
        then: validator.object().keys({
          id: validator.string().required()
        })
      })
    });


   const resultSuccess = validator.validate(bodyWhenValidDefined,schema);
    console.log("This is with success in validation",resultSuccess.value);

    const result = validator.validate(bodyWhenUndefined,schema);
    console.log("This is with default context property",result.value);


    const resultWithEmptyError = validator.validate(bodyWhenDefinedEmpty,schema);
    console.log("This should come with error with required property session",resultWithEmptyError.error);

    const resultWithWrongProp = validator.validate(bodyWhenDefinedWrong,resultWithWrongProp.error);


我已经创建了一个有效的REPL小提琴here,可以帮助您告诉我我做错了什么地方。

解决方法

因此,感谢REPL找到了here。我想到了如何基于同级属性值定义嵌套模式的想法。您只需为对象提供then条件并定义所需的属性。这是工作模式:

  const schema = validator.object().keys({
    user: validator.any().valid(Object.values(allowedUser)).required(),message: validator.string(),context: validator
      .object()
      .when('user',{
        is: allowedUser.admin,then: {
          session: validator.required()
        }
      })
      .when('user',{
        is: allowedUser.normal,then: {
          id: validator.required()
        }
      })
      .default({})
  });