I have this Joi schema:
let schema = {};
let stations = {
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: {
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').required().error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
},
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
};
schema.stations = Joi.array().items(stations).min(1).max(5).required().error(JoiCustomErrors);
As you can see, schema.stations
is an array of min 1 and max 5 elements.
I want that each of the elements will have the field of "address.place" only if the "contact.first_name" AND "contact.last_name" AND "contact.phone"
exists (or filled properly based on the schema).
How can I do that?
The validation is done using the Joi.validate () method, with the following signature: data: the data to validate which in our case is req.body. schema: the schema with which to validate the data. options: an object that specifies the validation options. Here are the validation options we used:
It is recommended that you create object schemas using Joi.object () or Joi.object ().keys (). When using any of these two methods, you can further control the keys that are allowed in the object using some additional constraints, which will not be possible to do using the object literal method.
After familiarizing yourself with constraints and schemas in Joi, you can now create the validation schemas for the API routes. Create a new file named schemas.js in the project route directory: Start by requiring Joi: The /people endpoint will use personDataSchema. In this scenario, an administrator is creating accounts for teachers and students.
You will create a REST API for this tutorial using Express to test your Joi schemas. To begin, open your command line terminal and create a new project directory: Then navigate to that directory: Run the following command to set up a new project: And install the required dependencies:
You can use the Joi.when()
method and create a schema like this:
Joi.object().keys({
contact: Joi.object().keys({
first_name: Joi.string(),
last_name: Joi.string(),
phone: Joi.string(),
}),
address: Joi.object().keys({
place: Joi.string(),
city: Joi.string().min(2).max(30),
street: Joi.string(),
house_number: Joi.string()
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.exist(),
last_name: Joi.exist(),
phone: Joi.exist(),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({ place: Joi.forbidden() })
}),
passengers_amount: Joi.number(),
notes: Joi.string()
});
I just simplified your schema so it's easy to understand.
Basically, what we are saying here is, if contact.first_name, contact.last_name and contact.phone exists, then address and address.place are required, otherwise address.place is forbidden.
For instance, this object will fail, because address does not exist:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
}
}
and this will fail because address.place does not exist:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
}
}
Finally, according to the schema defined, this object will pass:
{
contact: {
first_name: 'a',
last_name: 'b',
phone: 'c'
},
address: {
place: 'd'
}
};
Thanks to Soltex, thats the right schema that should be used (but please refer to the changes I have made):
Joi.object().keys({
contact: {
first_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
last_name: Joi.string().min(2).max(10).regex(Regex.alphabeta, 'alphabeta').allow("").error(JoiCustomErrors),
phone: Joi.string().min(10).max(10).regex(Regex.num, 'num').allow("").error(JoiCustomErrors),
},
address: Joi.object().keys({
place: Joi.string().min(2).max(10).regex(Regex.alphanum, 'alphanum').error(JoiCustomErrors),
city: Joi.string().min(2).max(30).required().error(JoiCustomErrors),
street: Joi.string().min(2).max(30).regex(Regex.alphabeta, 'alphabeta').required().error(JoiCustomErrors),
house_number: Joi.string().min(1).max(6).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
}).when('contact', {
is: Joi.object().keys({
first_name: Joi.string().min(1),
last_name: Joi.string().min(1),
phone: Joi.string().min(1),
}),
then: Joi.object({ place: Joi.required() }).required(),
otherwise: Joi.object({
place: Joi.optional().allow("")
})
}),
passengers_amount: Joi.number().min(0).max(4).required().error(JoiCustomErrors),
notes: Joi.string().min(2).max(100).regex(Regex.alphanum, 'alphanum').allow("").error(JoiCustomErrors)
})
Please note that changes from my answer to Soltex's answer: he made the when "contact.first_name" "contact.last_name" "contact.phone" to be: Joi.exists(). That is not good, since in such a way even an empty object is "exists" and then require the user to provide the "address.place". We don't want such a thing, we need at leat one char in each of those fields.
Plus, the otherwise statement in Soltex's answers is using the Joi.forbidden() while this is not the desired behaviour in here - we still need to allow the user to provide place, even without a contact, but this shouldn't be mandatory - so I used the: Joi.optional() instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With