Look at this phrase:
alternatives.conditional()
will use the first matching schema, ignoring other conditional statements.
If you have multiple conditionals()
only the first matching one affects the schema of the key.
Joi.object({
a: Joi.alternatives()
.conditional("c", { is: Joi.number().min(10), then: Joi.forbidden() })
.conditional("b", {
is: Joi.exist(),
then: Joi.valid("y"),
otherwise: Joi.valid("z"),
}),
b: Joi.any(),
c: Joi.number(),
});
For the above schema, if the object does not have key c
less than 10, only then the second conditional comes into effect.
Meaning
{ a : 'z' , c : 11 , b : 2 }
will say , "a" is not allowed (first condition).
But { a : 'z' , c : 7 , b : 2 }
will say , "a" must be [y] (second condition).
If you tweak the above condition to do something like this (I have only added an otherwise
clause):
Joi.object({
a: Joi.alternatives()
.conditional("c", {
is: Joi.number().min(10),
then: Joi.forbidden(),
otherwise: Joi.valid("x"),
})
.conditional("b", {
is: Joi.exist(),
then: Joi.valid("y"),
otherwise: Joi.valid("z"),
}),
b: Joi.any(),
c: Joi.number(),
});
then you have an invalid schema with the error: Unreachable condition
. Because here the first condition will definitely result in something (It has both then
and otherwise
).
But according to this:
When you use any.when()
you end up with composite schema of all the matching conditions
With any.when()
the whole chain is read until end, to decide the final schema.
const schema = {
a: Joi.any()
.valid("x")
.when("b", {
is: Joi.exist(),
then: Joi.valid("y"),
otherwise: Joi.valid("z"),
})
.when("c", { is: Joi.number().min(10), then: Joi.forbidden() }),
b: Joi.any(),
c: Joi.number(),
};
when b
exists, then y
is a valid value for a
, but when c
is a number greater than equal to 10
then a
is not allowed.
For example below is a valid object for above schema:
{
a: 'y', //'x' also works
b: 20,
c: 9
}
but this is not:
{
a: 'y',
b: 20,
c: 10
}
Also, alternatives add an extra alternative to try and do not affect the original type.
Look at the below schema:
Joi.object({
a: Joi.alternatives(["x"]).conditional("b", {
is: true,
then: Joi.forbidden(),
}),
b: Joi.boolean(),
});
{ b: true, a: 'x' }
will pass it. Joi.forbidden()
cannot affect the fact that x
is on of the valid values. If you pass { b: true , a: 'y' }
, this will definitely fail and you will see "a" is not allowed
.
If you write the above rule with when
:
Joi.object({
a: Joi.valid("x").when("b", { is: true, then: Joi.forbidden() }),
b: Joi.boolean(),
});
then, { b : true, a: 'x' }
will fail as expected because when
can affect the overall type of the key.
conditional().conditional()
vswhen().when()
). Are they at all different if composite? (conditional(conditional()) vs when(when())
)? – Mccollough