11

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?

HolySamosa
  • 9,011
  • 14
  • 69
  • 102
  • can you just remove `required`? – Giuseppe Pes May 21 '15 at 20:21
  • 1
    During creation, I want to enforce `required`. Lacking an option to ignore `required` during validation, I'm thinking I may need to create two schemas-- one for creation, another for updates. – HolySamosa May 21 '15 at 20:28

5 Answers5

6

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.

georgesamper
  • 4,989
  • 5
  • 40
  • 59
4

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
danielcorreia
  • 2,108
  • 2
  • 24
  • 36
1

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: "me@mail.com"}, "post");//error: "password is a required field" 
//For PUT 
const { error } = validateUser({email: "me@mail.com"}, "put");//error: undefined (no error)
Eme Hado
  • 390
  • 1
  • 4
  • 9
0

use .when() and set .required() according to the conditions.

vipulsodha
  • 624
  • 1
  • 9
  • 27
0

You can skip Joi validation by replace Joi.string()... to the exact value which you are passing as username. In the example i have passed empty username to api.

Also in condition basis, you can skip joi validation

let userSchema = Joi.object({
   username: "",
   email: <some condition> === true ? "" : Joi.string().required()
})
Alwin Jose
  • 696
  • 1
  • 5
  • 13