Home > Blockchain >  How to validate that an object property is required?
How to validate that an object property is required?

Time:11-25

I have object types that have a 'translations' property where the fields that can be translated into different languages are passed into the specific 'lang' property as you can see in the schema below.

An English translation is always required and the rest of the languages are optional, I can achieve this by setting .default(undefined) to the optional languages.

When a language is present and the validation for its inner fields fails, the error is always associated to the field itself ('name' in this case). This behaviour is expected.

What I else want to achieve and I don't know how is to show an error when the 'translations' property 'en' is not present with a message like 'An English translation is required'.

const categoryTranslationsSchema = object({
    name: string()
        .min(3, 'Must have at least 3 characters.')
        .max(16, 'Cannot be longer than 16 characteres.')
        .required('Must provide a name.')
})

const categorySchema = object({
    slug: string()
        .min(3, 'Must have at least 3 characters.')
        .max(16, 'Cannot be longer than 16 characteres.')
        .lowercase()
        .trim()
        .matches(/^(?![0-9-] $)(?:[a-z]{2,}-?|[0-9]-?) (?<!-)$/gm, 'Must start with a letter and can'
              ' only contain letters, numbers or dashes (no more than one consecutive).')
        .required('The slug is required.'),
    translations: object({
        en: categoryTranslationsSchema,
        es: categoryTranslationsSchema
            .default(undefined),
        de: categoryTranslationsSchema
            .default(undefined)
    })
})

CodePudding user response:

I think you should look into using a custom locale dictionary. Which allows you to customize the default messages used by Yup, when no message is provided with a validation test. If any message is missing in the custom dictionary the error message will default to Yup's one. It also provided enables multi-language support. https://github.com/jquense/yup#using-a-custom-locale-dictionary

import { setLocale } from 'yup';

setLocale({
  mixed: {
    default: 'Não é válido',
  },
  number: {
    min: 'Deve ser maior que ${min}',
  },
});

// now use Yup schemas AFTER you defined your custom dictionary
let schema = yup.object().shape({
  name: yup.string(),
  age: yup.number().min(18),
});

schema.validate({ name: 'jimmy', age: 11 }).catch(function (err) {
  err.name; // => 'ValidationError'
  err.errors; // => ['Deve ser maior que 18']
});

If you can't get what you're looking for with just that try combining it with yup.lazy which creates a schema that is evaluated at validation/cast time. This can be nested inside your object schema as well. https://github.com/jquense/yup#yuplazyvalue-any--schema-lazy

here is an idea of what you can do:

translations: Yup.lazy(value => {
      switch (typeof value) {
        case 'object':
          return Yup.object(); // schema for object
        case 'string':
          return Yup.string().min(MIN_DESC_LENGTH).max(_MAX_NAME_LENGTH); // schema for string
        default:
          return Yup.mixed(); // here you can decide what is the default
      }
      })

CodePudding user response:

Well, the problem when validating nested object is that they default to empty objects {}, for that reason it passes the validation and enters the inner validation.

The solution is then making all objects .default(undefined) that way we can add more requirements to the object validation itself, in this case making it required.

So the solution was as simple as that:

const categorySchema = object({
    slug: string()
        .min(3, 'Must have at least 3 characters.')
        .max(16, 'Cannot be longer than 16 characteres.')
        .lowercase()
        .trim()
        .matches(/^(?![0-9-] $)(?:[a-z]{2,}-?|[0-9]-?) (?<!-)$/gm, 'Must start with a letter and can'
              ' only contain letters, numbers or dashes (no more than one consecutive).')
        .required('The slug is required.'),
    translations: object({
        en: categoryTranslationsSchema
            .default(undefined)
            .required('An English translation must be provided.'),
        zh: categoryTranslationsSchema
            .default(undefined)
    }).default(undefined)
        .required('Translations must be defined.'),
})
  • Related