【问题标题】:Joi validator conditional schemaJoi 验证器条件模式
【发布时间】:2020-05-08 17:14:33
【问题描述】:

我需要根据请求查询中的键使用Joi validator 创建动态模式来验证我在node js 中的api 请求查询。假设下面提到的模式是我的有效查询。

我正在使用hapi/joi 版本16.1.8

组合1

{ type: 1, firstname: 'user first name', lastname: 'user last name'}

组合2

{ type: 2 , salary: 1000, pension: 200}

组合3

{ type: 3 , credit: 550, debit: 100}

如您所见,对象键因type 的值而异。如何妥善处理?

我们可以使用Joi.alternatives like 处理两种情况

const schema = Joi.alternatives().conditional(Joi.object({ type: 1 }).unknown(), {
    then: Joi.object({
        type: Joi.string(),
        firstname: Joi.string(),
        lastname: Joi.string()
    }),
    otherwise: Joi.object({
        type: Joi.number(),
        salary: Joi.any(),
        pension: Joi.any()
    })
});

但是如何在 3 个条件下做到这一点呢?

【问题讨论】:

  • 我会编写路由前中间件,它将有条件地定义要使用的模式。但是对于您的问题,Grégory NEUT 的答案是最合适的。
  • @num8er 我尝试了文档中的解决方案,它也是正确的。但是当我尝试添加相同的错误时,我抛出了一个错误。我已经更新了另一个工作示例作为答案。
  • 如何根据数据类型应用验证,例如数据类型是否为数组,然后检查数组中的每个项目,否则如果它是字符串,则验证必须是其他内容。例如。数据 = [1,2,3] 或数据 = '1'。这里如果数据是数组,则检查每个元素是否为数字,否则只需检查数据是否为数字
  • @user2459780 你可以用Joi.alternatives()实现这个目标

标签: javascript node.js hapijs joi


【解决方案1】:

documentation 中看起来switch 是与alternatives.conditional 一起使用的有效密钥。您可以尝试以下方法吗?

const schema = Joi.alternatives().conditional(Joi.object({
  type: 1
}).unknown(), {
  switch: [{
    is: 1,

    then: Joi.object({
      type: Joi.string(),
      firstname: Joi.string(),
      lastname: Joi.string(),
    }),
  }, {
    is: 2,

    then: Joi.object({
      type: Joi.number(),
      salary: Joi.any(),
      pension: Joi.any(),
    }),
  }, {
    // ...
  }],
});

编辑

在任何地方都找不到任何关于使用 switch 关键字的示例...

但在hapijs/joi github中找到了其他方法来实现它

const schema = Joi.object({
     a: Joi.number().required(),
     b: Joi.alternatives()
             .conditional('a', [
                 { is: 0, then: Joi.valid(1) },
                 { is: 1, then: Joi.valid(2) },
                 { is: 2, then: Joi.valid(3), otherwise: Joi.valid(4) }
    ])
});

【讨论】:

  • 这给我一个错误Error: "switch" can not be used with a schema condition。我正在使用hapi/joi 版本16.1.8
  • @Nitheesh 16.1.8 还提到了 switch 关键字。这意味着我们以错误的方式使用它,让我看看我能找到的一些例子
  • 您的第二种语法是正确的。我发布的答案在我的情况下也是相同的实现。谢谢:)
【解决方案2】:

我以不同的方式实现了同样的目标。在这里发布相同的内容,因为这可能对将来的某人有用。

const schema = Joi.object({
    type: Joi.number().required().valid(1, 2, 3),
    firstname: Joi.alternatives().conditional('type', { is: 1, then: Joi.string().required() }),
    lastname: Joi.alternatives().conditional('type', { is: 1, then: Joi.string().required() }),
    salary: Joi.alternatives().conditional('type', { is: 2, then: Joi.number().required() }),
    pension: Joi.alternatives().conditional('type', { is: 2, then: Joi.number().required() }),
    credit: Joi.alternatives().conditional('type', { is: 3, then: Joi.number().required() }),
    debit: Joi.alternatives().conditional('type', { is: 3, then: Joi.number().required() }),
}))

按预期完美运行。

当类型值为1 时,对象应该只有typefirstnamelastname

当类型值为2 时,对象应该只有typesalarypension

当类型值为3 时,对象应该只有typecreditdebit

任何其他组合都会从 joi 验证器中间件层作为错误抛出。除 1、2 和 3 之外的任何其他类型值也会引发错误。

【讨论】:

    【解决方案3】:

    它对我有用!

    var Joi = require('joi');
    
    var schema = {
        a: Joi.any().when('b', { is: 5, then: Joi.required(), otherwise: Joi.optional() }),
        b: Joi.any()
    };
    
    var thing = {
        b: 5
    };
    var validate = Joi.validate(thing, schema);
    
    // returns
    {
        error: null,
        value: {
            b: 5
        }
    }
    

    这是reference

    【讨论】:

    • 谢谢。这对我有用。非常清晰且易于重复使用。
    【解决方案4】:

    我试图找到一种方法来做类似的事情。然后我就弄明白了。

    const Joi = require('joi');
    const schema = Joi.object({
      type: Joi.number().valid(1,2,3),
      // anything common
    }).when(Joi.object({type: Joi.number().valid(1)}).unknown(), {
      then: Joi.object({
        firstname: Joi.string(),
        lastname: Joi.string(),
      })
    })
    .when(Joi.object({type: Joi.number().valid(2)}).unknown(), {
      then: Joi.object({
        salary: Joi.number(),
        pension: Joi.number(),
      })
    })
    .when(Joi.object({type: Joi.number().valid(3)}).unknown(), {
      then: Joi.object({
        credit: Joi.number(),
        debit: Joi.number(),
      })
    });
    
    

    【讨论】:

      【解决方案5】:

      我希望做同样的事情,但条件应该取决于请求方法,而不是查询参数。我最终得到了下一个解决方案:

      const schema = Joi.when(Joi.ref("$requestMethod"), {
        switch: [
          {
            is: "POST",
            then: Joi.object({
              name: Joi.string().trim().max(150).required(),
              description: Joi.string().max(255),
              active: Joi.boolean().required(),
              }),
            }),
          },
          {
            is: "PUT",
            then: Joi.object({
              name: Joi.string().trim().max(150).required(),
              description: Joi.string().max(255),            
            }),
          },
        ],
      });
      
      
      schema.validate(req.body, { context: { requestMethod: req.method } });
      

      Joi when() 条件文档https://joi.dev/api/?v=17.4.1#anywhencondition-options

      【讨论】:

        【解决方案6】:

        使用条件/开关,其语法也更易读。

        以下 Joi 摘录将在 $.type === Type.REFERENCE 时强制存在 $.referenceClass。当它这样做时,它将确保值是可接受的值 - ...classIds

        否则 ($.type !== Type.REFERENCE),它将不允许存在 $.referenceClass(除非您使用允许额外密钥的选项运行验证)。

        {
            type: Joi.string().valid( ...Hub.types ).required(),
            referenceClass: Joi.alternatives().conditional( 'type', {
                switch: [
                    { is: Type.REFERENCE, then: Joi.string().valid( ...classIds ) },
                ],
            } ),
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-18
          • 2021-04-16
          • 2020-08-10
          • 1970-01-01
          • 2021-10-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多