Joi conditional based on value of it's key (self-reference)

757 views Asked by At

I have an existing schema like this

exports.updateSchema = Joi.object({
  class_id: Joi.string().guid({ version: 'uuidv4' }).required(),
});

Existing only allow uid value, but now I also wanna allow specific string like general. So I need a schema that has conditional based on it's value, if try many ways using ref like this

exports.updateSchema = Joi.object({
  class_id: Joi.string().when(
    Joi.ref('.class_id'), {
      not: Joi.string().guid({ version: 'uuidv4' }),
      then: Joi.string().valid('general').required(),
      otherwise: Joi.string().guid({ version: 'uuidv4' }).required(),
    },
  ),
});

but no one works well.

And also tried this one

exports.updateGradeParamsSchema = Joi.object({
  class_id: Joi.string(),
}).when(Joi.object({ class_id: 'general' }).unknown(), {
  then: Joi.object({
    class_id: Joi.string().valid('general').required()
  }),
  otherwise: Joi.object({
    class_id: Joi.string().guid({ version: 'uuidv4' }).required()
  }),

but the error message is confusing, when I input 'john-doe', it's return

""class_id" must be a valid GUID"

instead of "class_id\" must be [general]

Is anyone ever do self-reference in Joi or is there another solutions for this?

UPDATE

Best approach

exports.updateSchema = Joi.object({
    class_id: Joi.alternatives().conditional('class_id', {
      not: Joi.string().guid({ version: 'uuidv4' }),
      then: Joi.string().valid('general').required(),
      otherwise: Joi.string().guid({ version: 'uuidv4' }).required()
    })
});

based on docs here it said this will use the first matching schema, ignoring other conditional statements

cons:

  • If I input uuid v1, it will match the first schema because the uuid is treat as string, and return \"class_id\" must be [general] instead of \"class_id\" must be a valid GUID
1

There are 1 answers

3
yanir midler On

Try this:

exports.updateSchema = Joi.object({
  grade_id: Joi.alternatives().try(
    Joi.string().guid({ version: 'uuidv4' }),
    Joi.string().valid('general')
  ).required()
});

This uses the alternatives method to try both guid validation for UUIDs and valid validation for the string "general". The required method is used to ensure that grade_id is present in the data.

I hope this helps!

If you want to return custom message:

exports.updateSchema = Joi.object({
  grade_id: Joi.string().when(
    Joi.ref('.grade_id'), {
      not: Joi.string().guid({ version: 'uuidv4' }),
      then: Joi.string().valid('general').required()
        .message('Grade ID must be a UUID or the string "general"'),
      otherwise: Joi.string().guid({ version: 'uuidv4' }).required()
        .message('Grade ID must be a UUID'),
    },
  ),
});