3

I have the following schema and json to validate using ajv. I am developing a REST API that takes a JSON and gets validated against the schema and it returns the error (400- with the ajv error) or (200 - when successfully validated)

const schema = {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [ "countries" ],
  "definitions": {
    "europeDef": {
      "type": "object",
      "required": ["type"],
      "properties": { "type": {"const": "europe"} }
    },
    "asiaDef": {
      "type": "object",
      "required": ["type"],
      "properties": { "type": {"const": "asia"} }
    }
  },
  "properties": {
    "countries": {
      "type": "array",
      "items": {
        "oneOf":[
          { "$ref": "#/definitions/europeDef" },
          { "$ref": "#/definitions/asiaDef"}
        ]
      }
    }
  }
}
const data = {
  "countries":[
    {"type": "asia1"},
    {"type": "europe1"}
  ]
}
const isValid = ajv.validate(schema, data); //schema, data
if(! isValid){
  console.log(ajv.errors);
}

and the error is:

[ { keyword: 'const',
    dataPath: '/countries/0/type',
    schemaPath: '#/definitions/europeDef/properties/type/const',
    params: { allowedValue: 'europe' },
    message: 'should be equal to constant' },
  { keyword: 'const',
    dataPath: '/countries/0/type',
    schemaPath: '#/definitions/asiaDef/properties/type/const',
    params: { allowedValue: 'asia' },
    message: 'should be equal to constant' },
  { keyword: 'oneOf',
    dataPath: '/countries/0',
    schemaPath: '#/properties/countries/items/oneOf',
    params: { passingSchemas: null },
    message: 'should match exactly one schema in oneOf' },
  { keyword: 'const',
    dataPath: '/countries/1/type',
    schemaPath: '#/definitions/europeDef/properties/type/const',
    params: { allowedValue: 'europe' },
    message: 'should be equal to constant' },
  { keyword: 'const',
    dataPath: '/countries/1/type',
    schemaPath: '#/definitions/asiaDef/properties/type/const',
    params: { allowedValue: 'asia' },
    message: 'should be equal to constant' },
  { keyword: 'oneOf',
    dataPath: '/countries/1',
    schemaPath: '#/properties/countries/items/oneOf',
    params: { passingSchemas: null },
    message: 'should match exactly one schema in oneOf' } ]

I know why the error is appearing (reason: as I have used 'asia1' & 'europe1' and it is not conforming the schema standard)

My question is, as I have derived this schema so I can pretty much understand the error. But for a third person it would definitely take some time to figure it out (and it may take more time, if the schema/errors are more complex).

If I returned that whole error message as a response as it is, it will be more complex error message to understand and to present to the enduser.

So, Is there any way by which I can provide more meaningful & user friendly error message to understand ? ex: Invalid countries values found in JSON

I have checked: ajv-errors, better-ajv-errors but they are not providing the exact way I want?

Can someone suggest how to do that in a more user friendly way or any alternative mechanism?

user8479984
  • 451
  • 2
  • 9
  • 23

1 Answers1

0

I am using below code for generating the human readable error message

let msg: string = "Wrong body" // fallback error message;
if (errors && errors.length > 0) {
  const error = errors[0];
  msg = `${error.instancePath} ${error.message}`;
}
res.status(4xx).json({
  errorMsg: msg,
});

I am using below dependencies to generate the validate functions in runtime with the below code

"dependencies": {
  "ajv": "^8.11.0",
  ... // other dependencies
}
"devDependencies": {
  "ajv-cli": "^5.0.0"
}

Below code gets run before project build and hence creating runtime generated validation files

const ajv = new Ajv({
  schemas: schemas, // list of parsed json *.json schemas
  code: { source: true, esm: true },
});
let moduleCode = standaloneCode(ajv);

Below is the few examples of error messaged diaplayed

  1. Case of missing property: "/items/0/price must have required property 'currency_code'"
  2. Case of additional property: "/address must NOT have additional properties"
  3. Case when quantity is fraction(allowed is +ve number): "/items/0/quantity must be integer"
  4. Case when quantity is -ve(allowed is +ve number): "/items/0/quantity must be >= 1"
  5. Case when passed value is not allowed(case of the enum): /items/0/price/currency_code must be equal to one of the allowed values
AndroidEngineX
  • 975
  • 1
  • 9
  • 22