Joi验证器的备选方案错误消息。

4

我正在尝试使用Joi.alternatives.try()创建 Joi 模式。这是我尝试过的模式。

Joi.alternatives().try(Joi.object({
    type: Joi.number().required().label('Error1!!')
}), Joi.object({
    reason: Joi.string().required().label('Error2!!')
})).label('Error!!')

这是我使用过的对象。

{ reason: 2 }

我原本期望的错误信息是包含字符串Error2!!Error2!!或其他错误信息。但实际上我收到的错误信息是:

验证错误:"Error !!"不匹配任何允许的类型。

该错误消息来自父节点。

如何使该错误信息更具体地指向该对象?例如,从替代对象节点而不是父对象节点返回的错误。

您可以使用这个平台在线验证模式。

更新: 下面是我使用的样例模式。

employee_retired = Joi.object({
    type: Joi.number().required().valid(2, 3, 7),
    reason: Joi.string().required()
        .min(1)
        .max(100),
    firstname: Joi.string()
        .required(),
    lastname: Joi.string()
        .required()
        .min(1)
        .max(255),
    personaldetails: Joi.alternatives().conditional('type', {
        is: 2, then: Joi.array().items(Joi.object({
            address: Joi.string().required()
                .min(1)
                .max(100),
            salary: Joi.string().required()
                .min(0)
                .max(500),
            contactnumbers: Joi.array().items(Joi.object({
                mobile: Joi.string().required()
                    .min(0)
                    .max(15),
                home: Joi.string()
                    .required()
                    .min(1)
                    .max(15),
            })).max(50).required(),
        }).required()).max(50).required(),
        otherwise: Joi.forbidden(),
    }),
    monthlysavings: Joi.alternatives().conditional('type', {
            is: 3,
            then: Joi.number()
                .required()
                .min(0)
                .max(50000),
            otherwise: Joi.forbidden(),
        }),
    isapproved: Joi.boolean().required(),
});

empolyee_working = Joi.object({
    type: Joi.number().required().valid(2, 3, 7),
    reason: Joi.string().required()
        .min(1)
        .max(100),
    firstname: Joi.string()
        .required(),
    lastname: Joi.string()
        .required()
        .min(1)
        .max(255),
    contactnumbers: Joi.array().items(Joi.object({
        mobile: Joi.string().required()
            .min(0)
            .max(15),
        home: Joi.string()
            .required()
            .min(1)
            .max(15),
    })).max(50).required(),
    monthlysavings: Joi.alternatives().conditional('type', {
        is: 3,
        then: Joi.number().required()
            .min(1)
            .max(50000),
        otherwise: Joi.forbidden(),
    }),
    isapproved: Joi.boolean().required(),
})

const employee = Joi.alternatives().try(employee_retired, empolyee_working);
1个回答

2

您可以使用object.or来实现此行为:

Joi.object({
    type: Joi.number().label('Error1!!'),
    reason: Joi.string().label('Error2!!')
}).or('type', 'reason').label('Error!!')

测试:

{}
// Validation Error: "Error!!" must contain at least one of [Error1!!, Error2!!]
{ reason: 2 }
// Validation Error: "Error2!!" must be a string
{ type: "a" } // note that due to default `convert` behavior, `{ type: "2" }` would pass
// Validation Error: "Error1!!" must be a number
{ a: "b" }
// Validation Error: "a" is not allowed. "Error!!" must contain at least one of [Error1!!, Error2!!]

更新(评论后)

的确,这样写可能有点啰嗦,但是遵循相同的逻辑:

  • 已经退休和在职的员工共享相同的结构
  • 只有personaldetailscontactnumbers不同

因此,以下代码应该会为您提供精确的验证错误消息(虽然我没有测试所有情况)。我只是“合并”了两个员工声明,两种变化的情况personaldetailscontactnumbers不再被声明为required,而是在最终的or中指定。

Joi.object({
    type: Joi.number().required().valid(2, 3, 7),
    reason: Joi.string().required()
        .min(1)
        .max(100),
    firstname: Joi.string()
        .required(),
    lastname: Joi.string()
        .required()
        .min(1)
        .max(255),
    personaldetails: Joi.alternatives().conditional('type', {
        is: 2, then: Joi.array().items(Joi.object({
            address: Joi.string().required()
                .min(1)
                .max(100),
            salary: Joi.string().required()
                .min(0)
                .max(500),
            contactnumbers: Joi.array().items(Joi.object({
                mobile: Joi.string().required()
                    .min(0)
                    .max(15),
                home: Joi.string()
                    .required()
                    .min(1)
                    .max(15),
            })).max(50).required(),
        // N.B.: no more .required() on the next line, .or() will handle it conditionally
        }).required()).max(50),
        otherwise: Joi.forbidden(),
    }),
    contactnumbers: Joi.array().items(Joi.object({
        mobile: Joi.string().required()
            .min(0)
            .max(15),
        home: Joi.string()
            .required()
            .min(1)
            .max(15),
    // N.B.: no more .required() on the next line, .or() will handle it conditionally
    })).max(50),
    monthlysavings: Joi.alternatives().conditional('type', {
            is: 3,
            then: Joi.number()
                .required()
                .min(0)
                .max(50000),
            otherwise: Joi.forbidden(),
        }),
    isapproved: Joi.boolean().required(),
}).or('personaldetails', 'contactnumbers').label('OR failure')

嗨@Stock Overflaw,感谢您的回复。我尝试了您的解决方案,似乎在这种情况下可以工作。但问题是,我在问题中提到的两个对象并不像一个简单键的对象那么简单。这些对象可能有多个键,其中可能是另一个对象或数组。这就是为什么我寻找替代方案的原因。我将在我的问题中更新一个需要的示例对象。我已经为您的回复标记了赞成票。抱歉回复晚了。 - Nitheesh
嗨@Nitheesh,我根据您展示的“真实”案例刚刚更新了答案。希望这能有所帮助! :) - Stock Overflaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接