Ajv custom error message for type
Asked Answered
F

2

10

i was exploring Ajv with ajv-errors for validating json schema and producing custom error messages. everything works as of now but i can't set custom error message for type for individual values.

const emailSchema = {
 type: 'object',
 required: ['foo', 'bar', 'car'],
 properties: {
  foo: { type: 'integer' },
  bar: { type: 'string' },
  car: { type: 'string' }
 },
 errorMessage: {
  type: 'should be an object',
  required: {
  foo: 'foo field is missing',
  bar: 'bar field is missing',
  car: 'car field is missing'
  }
 } 
};

outputs following error

[
    {
        "keyword": "type",
        "dataPath": "/foo",
        "schemaPath": "#/properties/foo/type",
        "params": {
            "type": "integer"
        },
        "message": "should be integer"
    },
    {
        "keyword": "errorMessage",
        "dataPath": "",
        "schemaPath": "#/errorMessage",
        "params": {
            "errors": [
                {
                    "keyword": "required",
                    "dataPath": "",
                    "schemaPath": "#/required",
                    "params": {
                        "missingProperty": "bar"
                    },
                    "message": "should have required property 'bar'"
                }
            ]
        },
        "message": "bar field is missing"
    },
    {
        "keyword": "errorMessage",
        "dataPath": "",
        "schemaPath": "#/errorMessage",
        "params": {
            "errors": [
                {
                    "keyword": "required",
                    "dataPath": "",
                    "schemaPath": "#/required",
                    "params": {
                        "missingProperty": "car"
                    },
                    "message": "should have required property 'car'"
                }
            ]
        },
        "message": "car field is missing"
    }
]

the first error object with message "should be integer", can i customize it like foo must be an Integer. I am expecting something like below but it gives be schema error.

type : {
  foo : "foo must be an Integer"
}

Thanks.

Flooded answered 10/3, 2018 at 18:41 Comment(0)
L
18

You must declare errorMessage as keyword inside each of properties, see this example:

const emailSchema = {
  type: 'object',
  required: ['foo', 'bar', 'car'],
  properties: {
    foo: {
      type: 'integer',
      errorMessage: {
        // In here must be errorMessage not errorMessages
        type: 'foo must be an Integer', // Your Custom Error Message
      },
    },
    bar: { type: 'string' },
    car: { type: 'string' },
  },
  errorMessages: {
    // Change from errorMessage to errorMessages
    type: 'should be an object',
    required: {
      foo: 'foo field is missing',
      bar: 'bar field is missing',
      car: 'car field is missing',
    },
  },
}

Ladle answered 26/9, 2018 at 13:4 Comment(0)
M
1

For use cases where we have some custom errorMessage or any other data, we have to use the schema path. When we get the validation error, we also get the error.keyword in my case I had extra validation in if and else block as below

schema.allOf= Object.keys(bankCodes).map((key: any) => ({
    if: {
      properties: {
        routingCodeType1: { const: bankCodes[key].code },
      },
    },
    then: {
      properties: {
        routingCodeValue1: {
          pattern: bankCodes[key].pattern, //<-- this was cause of validation fail
          errorMessage: bankCodes[key].errorMessage,
        },
      },
    },
  }))

so in the error.keyword I would get pattern as well as schemaPath=/#/allOf/2/then/properties/routingCodeValue1/pattern

so basically I would have to use this schema path to fetch the related data back from schema. Following code helped me with it

const getPatternMessage = (error: any, schema: any) => {
  if (error.keyword === 'pattern') {
    const fieldName = error.dataPath.substring(1); // routingCodeValue1
    const keyArr = error.schemaPath.split('/'); // ['#','allOf','2'..,'pattern']
    keyArr.pop(); // remove '#'
    keyArr.shift(); // remove 'pattern'
    const prop = keyArr.reduce((acc, key) => acc[key], schema);
/** 
prop contains  {
          pattern: '^[a-z]{9}$',
          errorMessage:'routingCodeValue1 should be 9 characters'
        },
*/
    return {
      [fieldName]: prop.errorMessage,
    };
  }
};

This way we are able to extract get custom errorMessage or any other data we want

Gist is to use the schemaPath property

Mcsweeney answered 6/11, 2020 at 12:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.