简体   繁体   English

Joi 验证器条件模式

[英]Joi validator conditional schema

I need to create dynamic schema to validate my api request query in node js using Joi validator depending on a key in the request query.我需要创建动态模式以根据请求查询中的键使用Joi 验证器node js验证我的 api 请求查询。 Say the following below mentioned pattern are my valid queries.说下面提到的模式是我的有效查询。

I'm using hapi/joi version 16.1.8我正在使用hapi/joi 16.1.8版本16.1.8

Combination 1组合1

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

Combination 2组合2

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

Combination 3组合3

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

As you can see the object keys varies depending on the value of type .如您所见,对象键因type的值而异。 How this can be handled properly?如何正确处理?

We can handle two conditions using Joi.alternatives like我们可以使用Joi.alternatives处理两个条件,例如

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()
    })
});

But how this can be done for 3 conditions?但是如何在 3 个条件下做到这一点?

I achieved the same in a little different manner.我以稍微不同的方式实现了相同的目标。 Posting the same here since this might be useful for someone in future.在这里发布相同的内容,因为这可能对将来的某人有用。

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() }),
}))

This was working perfectly as expected.这正如预期的那样完美地工作。

When the type value is 1 the object should have only type , firstname and lastname当类型值为1 ,对象应该只有typefirstnamelastname

When the type value is 2 the object should have only type , salary and pension当类型值为2 ,对象应该只有typesalarypension

When the type value is 3 the object should have only type , credit and debit当 type 值为3 ,对象应该只有typecreditdebit

Any other combination will be thrown as error from the joi validator middleware layer.任何其他组合都将从 joi 验证器中间件层作为错误抛出。 Also any other type value other that 1, 2 and 3 will be throwing error.此外,除 1、2 和 3 之外的任何其他类型值都将引发错误。

It works for me!这个对我有用!

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
    }
}

This is the reference .这是 参考

In the documentation it look like switch is valid key to use along alternatives.conditional .文档中,看起来switch是与alternatives.conditional一起使用的有效键。 Could you try the following ?您可以尝试以下方法吗?

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(),
    }),
  }, {
    // ...
  }],
});

EDIT :编辑

Couldn't find any example anywhere about the use of the switch keyword...在任何地方都找不到有关使用switch关键字的任何示例...

But found some other way to achieve it in hapijs/joi github但是在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) }
    ])
});

I was trying to find a way to do something similar.我试图找到一种方法来做类似的事情。 Then I was able to figure it out.然后我就想通了。

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(),
  })
});

I was looking to do the same but instead of query param the condition should depend on the request method.我想做同样的事情,但条件应该取决于请求方法而不是查询参数。 I ended up with the next solution:我最终得到了下一个解决方案:

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() condition documentation https://joi.dev/api/?v=17.4.1#anywhencondition-options Joi when() 条件文档https://joi.dev/api/?v=17.4.1#anywhencondition-options

Using the conditional/switch, of which syntax is also more readable.使用条件/开关,其语法也更具可读性。

The following Joi excerpt will enforce the presence of $.referenceClass when $.type === Type.REFERENCE .以下 Joi 摘录将在$.type === Type.REFERENCE时强制$.referenceClass的存在。 When it does, it will ensure that values are the accepted ones - ...classIds .当它这样做时,它将确保值是接受的值 - ...classIds

Otherwise ( $.type !== Type.REFERENCE ), it won't allow the presence of $.referenceClass (except you run the validation with the option of allowing extra keys).否则( $.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 ) },
        ],
    } ),
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM