Joi: Building a schema with conditional validation, based on external factors

Created on 12 Dec 2018  路  8Comments  路  Source: sideway/joi

Describe the problem you are trying to fix (provide as much context as possible)

I did some digging on the docs, SO and source and didn't find anything about this, but I can be wrong.
What I need to do is only validate some keys when an external condition is met. Different from what we have today, that the condition is based on the object that is being validated.

//buildUserSchema.js
export default ({  ageIsRequired }) => {
  const userSchemaKeys = {
      name: Joi.string().min(2).required().label('Name'),
      lastName: Joi.string().min(3).required().label('Last name'),
  };

  if (ageIsRequired) {
      userSchemaKeys.age = Joi.number().positive().required().label('Age');
  }

  return Joi.object(userSchemaKeys);
}

This is an oversimplified example, I could have several xxxIsRequired to check.

Which API (or modification of the current API) do you suggest to solve that problem?

Maybe we could do some like:

//buildUserSchema.js
export default ({  ageIsRequired }) => Joi.object({
    name: Joi.string().min(2).required().label('Name'),
    lastName: Joi.string().min(3).required().label('Last name'),
    age: Joi.number().positive().label('Age').required(ageIsRequired) //or .required(() => ageIsRequired)
});

The thing is if ageIsRequired then I must validate it, otherwise I need to completely ignore the key.

Thanks in advance.

Are you ready to work on a pull request if your suggestion is accepted?

Yes.

support

Most helpful comment

This is also an option, but then I would need to create an array based on my requirements, it's almost what I had, in my first question.
I believe I'm going with the approach mentioned by @WesTyler for now.
Just changed everything here, and it seems to be a valid option for me.

Thanks!

All 8 comments

Have you looked into using the context refs described here?

something like

const schema = Joi.object().keys({
    conditional: Joi.number().when('$condition', {
        is: Joi.boolean().valid(true).required(),
        then: Joi.required(),
        otherwise: Joi.optional()
    })
});

schema.validate({}); // error: null
schema.validate({}, {context: {condition: false}}); // error: null
schema.validate({}, {context: {condition: true}}); // ValidationError: child "conditional" fails because ["conditional" is required]

The benefit of using the validation context instead of your proposal is that the validation context can pull the value at validation time, whereas I believe doing it in the schema composition would effectively freeze the require value based on the external variable's value at schema compile time.

Hey @WesTyler, thanks for the response!
Yeah, I believe this could help me, for me this wasn't clear, about the possibility to use those context values with the .when.

I'll need to change some stuff to be able to use this approach since the schema.validate is being called by another part of the application.

I'm going to close this.
Thanks for your help!

Just wondering, why don't you just define 2 schemas like so?

const schema = Joi.object({
    name: Joi.string().min(2).required().label('Name'),
    lastName: Joi.string().min(3).required().label('Last name'),
});

const schemaWithAge = schema.keys({
    age: Joi.number().positive().required().label('Age')
})

export default ({ ageIsRequired }) => {

    return ageIsRequired ? schemaWithAge : schema;
}

As I said, I oversimplified the example.
In reality, I can have this isRequired check for virtually any key (except id and some other exceptions).

Then would a simple schema with a call to requiredKeys work?

This is also an option, but then I would need to create an array based on my requirements, it's almost what I had, in my first question.
I believe I'm going with the approach mentioned by @WesTyler for now.
Just changed everything here, and it seems to be a valid option for me.

Thanks!

This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

n-sviridenko picture n-sviridenko  路  3Comments

normancarcamo picture normancarcamo  路  3Comments

kevbook picture kevbook  路  4Comments

Taxi4you picture Taxi4you  路  3Comments

mohamadresaaa picture mohamadresaaa  路  3Comments