I need to create dynamic schema to validate my api request query in node js
using Joi validator depending on a key in the request query. Say the following below mentioned pattern are my valid queries.
I'm using hapi/joi
version 16.1.8
Combination 1
{ type: 1, firstname: 'user first name', lastname: 'user last name'}
Combination 2
{ type: 2 , salary: 1000, pension: 200}
Combination 3
{ type: 3 , credit: 550, debit: 100}
As you can see the object keys varies depending on the value of type
. How this can be handled properly?
We can handle two conditions using Joi.alternatives like
const schema = Joi.alternatives().conditional(Joi.object({ type: 1 }).unknown(), {
then: Joi.object({
type: Joi.string(),
firstname: Joi.string(),
lastname: Joi.string()
}),
otherwise: Joi.object({
type: Joi.number(),
salary: Joi.any(),
pension: Joi.any()
})
});
But how this can be done for 3 conditions?
Schema validation middleware for create account requests in Node.js with joi This example Node.js middleware function validates a request to create a new account. It defines schema rules with the joi schema validation library and calls schema.validate (req.body, options) to determine if the request is valid.
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:
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.
Sometimes, you may want a value to be either a string or number or something else. This is where alternative schemas come into play. You can define alternative schemas using Joi.alternatives (). It inherits from the any () schema, so constraints like required () can be used with it.
I achieved the same in a little different manner. Posting the same here since this might be useful for someone in future.
const schema = Joi.object({
type: Joi.number().required().valid(1, 2, 3),
firstname: Joi.alternatives().conditional('type', { is: 1, then: Joi.string().required() }),
lastname: Joi.alternatives().conditional('type', { is: 1, then: Joi.string().required() }),
salary: Joi.alternatives().conditional('type', { is: 2, then: Joi.number().required() }),
pension: Joi.alternatives().conditional('type', { is: 2, then: Joi.number().required() }),
credit: Joi.alternatives().conditional('type', { is: 3, then: Joi.number().required() }),
debit: Joi.alternatives().conditional('type', { is: 3, then: Joi.number().required() }),
}))
This was working perfectly as expected.
When the type value is 1
the object should have only type
, firstname
and lastname
When the type value is 2
the object should have only type
, salary
and pension
When the type value is 3
the object should have only type
, credit
and debit
Any other combination will be thrown as error from the joi validator middleware layer. Also any other type value other that 1, 2 and 3 will be throwing error.
It works for me!
var Joi = require('joi');
var schema = {
a: Joi.any().when('b', { is: 5, then: Joi.required(), otherwise: Joi.optional() }),
b: Joi.any()
};
var thing = {
b: 5
};
var validate = Joi.validate(thing, schema);
// returns
{
error: null,
value: {
b: 5
}
}
This is the reference.
In the documentation it look like switch
is valid key to use along alternatives.conditional
. Could you try the following ?
const schema = Joi.alternatives().conditional(Joi.object({
type: 1
}).unknown(), {
switch: [{
is: 1,
then: Joi.object({
type: Joi.string(),
firstname: Joi.string(),
lastname: Joi.string(),
}),
}, {
is: 2,
then: Joi.object({
type: Joi.number(),
salary: Joi.any(),
pension: Joi.any(),
}),
}, {
// ...
}],
});
EDIT :
Couldn't find any example anywhere about the use of the switch
keyword...
But found some other way to achieve it in hapijs/joi github
const schema = Joi.object({
a: Joi.number().required(),
b: Joi.alternatives()
.conditional('a', [
{ is: 0, then: Joi.valid(1) },
{ is: 1, then: Joi.valid(2) },
{ is: 2, then: Joi.valid(3), otherwise: Joi.valid(4) }
])
});
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