Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignoring "required" in Joi validation?

I'm attempting to use Joi to validate a data model accepted by a RESTful web service.

For a create operation, I want to enforce the "required" validation on fields. However, for an update operation, a partial data object may be submitted so I would like the "required" attributes to be ignored.

Is there a way to achieve this aside from creating two schemas?

like image 781
HolySamosa Avatar asked May 21 '15 20:05

HolySamosa


3 Answers

You can avoid the two schemas by extending the first one using optionalKeys.

const createSchema = Joi.object().keys({
  name: Joi.string().required(),
  birthday: Joi.date().required(),
});

const updateSchema = createSchema.optionalKeys("name", "birthday");

Joi.validate({name: "doesn't work"}, createSchema); // error: birthday field missing
Joi.validate({name: "it works"}, updateSchema); // all good
like image 110
danielcorreia Avatar answered Oct 06 '22 00:10

danielcorreia


With .fork() you can pass in an array of the fields you want to be required.

const validate = (credentials, requiredFields = []) => {

  // Schema
  let userSchema = Joi.object({
    username: Joi.string(),
    email: Joi.string().email(),
  })

  // This is where the required fields are set
  userSchema = userSchema.fork(requiredFields, field => field.required())

  return userSchema.validate(credentials)
}

validate(credentials, ['email'])

Or do the opposite and change them to optional.

like image 23
georgesamper Avatar answered Oct 06 '22 00:10

georgesamper


Your desired results can be achieved using the alter method. Here's an example.

const validateUser = (user, requestType) => {
  let schema = Joi.object({
    email: Joi.string().email().required(),
//Here, we want to require password when request is POST. 
//Also we want to remove password field when request is PUT
    password: Joi.string()
      .min(1)
      .max(256)
      .alter({
//For POST request
        post: (schema) => schema.required(),
//For PUT request
        put: (schema) => schema.forbidden(),
      }),
  });

  return schema.tailor(requestType).validate(user);
};

Then in our route we call the function and pass the arguments like so:

//For POST
const { error } = validateUser({email: "[email protected]"}, "post");//error: "password is a required field" 
//For PUT 
const { error } = validateUser({email: "[email protected]"}, "put");//error: undefined (no error)
like image 36
Eme Hado Avatar answered Oct 06 '22 02:10

Eme Hado