首页 > 解决方案 > Joi - 多个 `when` 子句

问题描述

我有两个验证要在同一个有效负载上执行:

hasSalary为真时,要么 要么monthlySalary必须annualSalary存在。

hasCosts为真时,要么 要么monthlyCosts必须annualCosts存在。

我将其编码为:

Joi.object({
  hasSalary: Joi.boolean(),
  monthlySalary: Joi.number(),
  annualSalary: Joi.number(),
  hasCosts: Joi.boolean(),
  monthlyCosts: Joi.number(),
  annualCosts: Joi.number(),
})
.when(
  Joi.object({ hasSalary: Joi.boolean().valid(true).required() }),
  {
    then: Joi.object().xor('monthlySalary', 'annualSalary')
  }
)
.when(
  Joi.object({ hasCosts: Joi.boolean().valid(true).required() }),
  {
    then: Joi.object().xor('monthlyCosts', 'annualCosts')
  }
);

这正确地给出了一个验证错误{ hasSalary: true }

message: '"value" must contain at least one of [monthlySalary, annualSalary]'

...对于{ hasCosts: true }

message: '"value" must contain at least one of [monthlyCosts, annualCosts]'

...但是当两个布尔值都是并且不满足true第二个约束时,它不能像我预期的那样工作:when

{
  hasSalary: true,
  monthlySalary: 300,
  hasCosts: true,
}

我希望在"value" must contain at least one of [monthlyCosts, annualCosts]这里,但我得到了一个没有错误的干净验证。

我想我明白发生了什么 - 链接whens 正在创建一系列守卫,第一个匹配的守卫获胜。

那么我可以在 Joi(最好是版本 15)中使用什么构造来实现我想要的?

标签: javascriptvalidationjoi

解决方案


使用最新版本Joi 17.2.1,您不会遇到此问题(当条件正确解决时会出现多个问题)

但是对于Joi 15.1.1,您可以使用以下解决方法:

const Joi = require('@hapi/joi');

const one = Joi.object({
  hasSalary: Joi.boolean().valid(true),
  monthlySalary: Joi.number(),
  annualSalary: Joi.number(),
}).xor('monthlySalary', 'annualSalary');

const two = Joi.object({
  hasSalary: Joi.boolean().valid(false),
  monthlySalary: Joi.number(),
  annualSalary: Joi.number(),
});

const three = Joi.object({
  hasCosts: Joi.boolean().valid(true),
  monthlyCosts: Joi.number(),
  annualCosts: Joi.number(),
}).xor('monthlyCosts', 'annualCosts');

const four = Joi.object({
  hasCosts: Joi.boolean().valid(false),
  monthlyCosts: Joi.number(),
  annualCosts: Joi.number(),
});

const one_three = one.concat(three);
const one_four = one.concat(four);
const two_three = two.concat(three);
const two_four = two.concat(four);

const schema = Joi.alternatives().try(
  one,
  two,
  three,
  four,

  one_three,
  one_four,
  two_three,
  two_four,
);

运行一些测试:

// works
const data1 = {
  hasSalary: true,
  monthlySalary: 2000,
};
console.log(schema.validate(data1).error);

// works
const data2 = {
  hasSalary: false,
};
console.log(schema.validate(data2).error);

// works
const data3 = {
  hasCosts: true,
  monthlyCosts: 300,
};
console.log(schema.validate(data3).error);

// works
const data4 = {
  hasCosts: false,
};
console.log(schema.validate(data4).error);

// works
const data5 = {
  hasSalary: true,
  monthlySalary: 2000,

  hasCosts: true,
  monthlyCosts: 300,
};
console.log(schema.validate(data5).error);

// works
const data6 = {
  hasSalary: false,

  hasCosts: true,
  monthlyCosts: 300,
};
console.log(schema.validate(data6).error);

// works
const data7 = {
  hasSalary: true,
  monthlySalary: 2000,

  hasCosts: false,
};
console.log(schema.validate(data7).error);

// works
const data8 = {
  hasSalary: false,

  hasCosts: false,
};
console.log(schema.validate(data8).error);

// error
const data9 = {
  hasSalary: true
};
console.log(schema.validate(data9).error.message)

// error
const data10 = {
  hasSalary: true,
  annualSalary: 1000,

  hasCosts: true,
};
console.log(schema.validate(data10).error.message)

推荐阅读