I have two validations to perform on the same payload:
When hasSalary is true, either monthlySalary or annualSalary must be present.
When hasCosts is true, either monthlyCosts or annualCosts must be present.
I have coded this as:
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')
}
);
This correctly gives a validation error for: { hasSalary: true }:
message: '"value" must contain at least one of [monthlySalary, annualSalary]'
... and for { hasCosts: true }:
message: '"value" must contain at least one of [monthlyCosts, annualCosts]'
... but doesn't work as I expected when both the booleans are true, and the second when's constraints are not met:
{
hasSalary: true,
monthlySalary: 300,
hasCosts: true,
}
I hoped for "value" must contain at least one of [monthlyCosts, annualCosts] here, but instead I got a clean validation with no error.
I think I understand what's happening - chaining whens is creating a series of guards, and the first matching one wins.
So what construct can I use in Joi (ideally version 15) to achieve what I wanted?