Yup: ValidationError type doesn't contain schema type

Created on 31 Aug 2019  路  1Comment  路  Source: jquense/yup

Each schema validator has a name.

Number min value rule has name min. String min length rule has name min. And array min length rule has min name.

In ValidationError rule name used for type property value.

If my number field is invalid - error type will be min.
If my string field has not enough length - error type will be min...

Why these names used? Not string.min, number.min?
Sometimes it can be helpful to have full error type.

We use this approach in an API validation error response:

{
  ...
  name: {
    message: 'name must be at least 5 characters',
    type: 'string.min',
    params:  { value: 1, min: 5 } ,
  },
}

It allows us to render error messages on the client as the client wants. Translate them if we don't want or can't support translates on the API side. Generate something like:

<div> Your name must be at least <b>5</b> characters</div>

etc.

So, any chance to think about using the full rules name? Or maybe there is a way to get it in ValidationError handler?

Most helpful comment

Maybe will be useful for somebody.
In our project we use this approach:

yup.setLocale({
  mixed: {
    default: { type: 'mixed.default' },
    required: { type: 'mixed.required' },
    oneOf: ({ values }) => ({ type: 'mixed.oneOf', params: { values } }),
    notOneOf: ({ values }) => ({ type: 'mixed.notOneOf', params: { values } }),
    notType: ({ type }) => ({ type: `${type}.base` }),
    defined: { type: 'mixed.defined' },
  },
  string: {
    length: ({ length }) => ({ type: 'string.length', params: { length } }),
    min: ({ min }) => ({ type: 'string.min', params: { min } }),
    max: ({ max }) => ({ type: 'string.max', params: { max } }),
    matches: ({ regex }) => ({ type: 'string.matches', params: { regex } }),
    email: { type: 'string.email' },
    url: { type: 'string.url' },
    trim: { type: 'string.trim' },
    lowercase: { type: 'string.lowercase' },
    uppercase: { type: 'string.uppercase' },
  },
  number: {
    min: ({ min }) => ({ type: 'number.min', params: { min } }),
    max: ({ max }) => ({ type: 'number.max', params: { max } }),
    lessThan: ({ less }) => ({ type: 'number.lessThan', params: { less } }),
    moreThan: ({ more }) => ({ type: 'number.moreThan', params: { more } }),
    notEqual: ({ notEqual }) => ({ type: 'number.notEqual', params: { notEqual } }),
    positive: { type: 'number.positive' },
    negative: { type: 'number.negative' },
    integer: { type: 'number.integer' },
  },
  date: {
    min: ({ min }) => ({ type: 'date.min', params: { min } }),
    max: ({ max }) => ({ type: 'date.max', params: { max } }),
  },
  object: {
    noUnknown: ({ unknown }) => ({ type: 'object.noUnknown', params: { unknown } }),
  },
  array: {
    min: ({ min }) => ({ type: 'array.min', params: { min } }),
    max: ({ max }) => ({ type: 'array.max', params: { max } }),
  },
});

We have a validate function which wraps schema.validate call and return validation error after formatting.

Result contains:

{
  type: 'ValidationError',
  details: {
    'path.to.field': {
      type: 'number.min', 
      value: 5,
      params: {
        min: 10,
      },
      message: 'Exists only if custom message defined in schema',
    }
  }
}

Next, we can add a message if it's not exist

details['path.to.field'].message = i18n(`validation.${details['path.to.field'].type}`, userLanguage, details['path.to.field'].params)

>All comments

Maybe will be useful for somebody.
In our project we use this approach:

yup.setLocale({
  mixed: {
    default: { type: 'mixed.default' },
    required: { type: 'mixed.required' },
    oneOf: ({ values }) => ({ type: 'mixed.oneOf', params: { values } }),
    notOneOf: ({ values }) => ({ type: 'mixed.notOneOf', params: { values } }),
    notType: ({ type }) => ({ type: `${type}.base` }),
    defined: { type: 'mixed.defined' },
  },
  string: {
    length: ({ length }) => ({ type: 'string.length', params: { length } }),
    min: ({ min }) => ({ type: 'string.min', params: { min } }),
    max: ({ max }) => ({ type: 'string.max', params: { max } }),
    matches: ({ regex }) => ({ type: 'string.matches', params: { regex } }),
    email: { type: 'string.email' },
    url: { type: 'string.url' },
    trim: { type: 'string.trim' },
    lowercase: { type: 'string.lowercase' },
    uppercase: { type: 'string.uppercase' },
  },
  number: {
    min: ({ min }) => ({ type: 'number.min', params: { min } }),
    max: ({ max }) => ({ type: 'number.max', params: { max } }),
    lessThan: ({ less }) => ({ type: 'number.lessThan', params: { less } }),
    moreThan: ({ more }) => ({ type: 'number.moreThan', params: { more } }),
    notEqual: ({ notEqual }) => ({ type: 'number.notEqual', params: { notEqual } }),
    positive: { type: 'number.positive' },
    negative: { type: 'number.negative' },
    integer: { type: 'number.integer' },
  },
  date: {
    min: ({ min }) => ({ type: 'date.min', params: { min } }),
    max: ({ max }) => ({ type: 'date.max', params: { max } }),
  },
  object: {
    noUnknown: ({ unknown }) => ({ type: 'object.noUnknown', params: { unknown } }),
  },
  array: {
    min: ({ min }) => ({ type: 'array.min', params: { min } }),
    max: ({ max }) => ({ type: 'array.max', params: { max } }),
  },
});

We have a validate function which wraps schema.validate call and return validation error after formatting.

Result contains:

{
  type: 'ValidationError',
  details: {
    'path.to.field': {
      type: 'number.min', 
      value: 5,
      params: {
        min: 10,
      },
      message: 'Exists only if custom message defined in schema',
    }
  }
}

Next, we can add a message if it's not exist

details['path.to.field'].message = i18n(`validation.${details['path.to.field'].type}`, userLanguage, details['path.to.field'].params)
Was this page helpful?
0 / 5 - 0 ratings