tdegrunt / jsonschema

JSON Schema validation
Other
1.82k stars 262 forks source link

Provide path to schema in ValidationError #365

Open ri0ter opened 2 years ago

ri0ter commented 2 years ago

It would be nice to include source of an error referring to schema. So for e.g. in following schema it would be easy to say where it came from:

    type: 'object',
    properties: {
      foo: { type: 'string', minLength: 2 },
      bar: { type: 'array' },
    },
    allOf: [
      {
        properties: {
          foo: {
            minLength: 1,
          },
        },
      }
    ]

At the moment, the schema will tell you that the problem is with the length of the value foo, but it's hard to tell which rule triggered actual error.

awwright commented 2 years ago

@ri0ter ValidationError#name is the property you're looking for. e.g.

validate("instance", {type:"number"}).errors[0].name // "type"
ri0ter commented 2 years ago

Not really, for the schema I mentioned in my first message, with input:

{
  foo: '',
},

I get 3 errors:

[
  {
    "path": [
      "foo"
    ],
    "property": "instance.foo",
    "message": "does not meet minimum length of 2",
    "schema": {
      "type": "string",
      "minLength": 2
    },
    "instance": "",
    "name": "minLength",
    "argument": 2,
    "stack": "instance.foo does not meet minimum length of 2"
  },
  {
    "path": [],
    "property": "instance",
    "message": "does not match allOf schema [subschema 0] with 1 error[s]:",
    "schema": {
      ...
    },
    "instance": {
      "foo": ""
    },
    "name": "allOf",
    "argument": {
      ...
    },
    "stack": "instance does not match allOf schema [subschema 0] with 1 error[s]:"
  },
  {
    "path": [
      "foo"
    ],
    "property": "instance.foo",
    "message": "does not meet minimum length of 1",
    "schema": {
      "minLength": 1
    },
    "instance": "",
    "name": "minLength",
    "argument": 1,
    "stack": "instance.foo does not meet minimum length of 1"
  }
]

As you can see you cannot differentiate what's the source of first and last error.

awwright commented 2 years ago

Can you please describe the exact information you're expecting?

Maybe you're looking for the "path" property? An empty array indicates an error in the root. The "foo" item indicates it is within that property in the instance.

awwright commented 2 years ago

Or if you need to know which subschema is applied, the "schema" property in the error is a reference to the original schema.

ri0ter commented 2 years ago

Well, the path property describes the instance and subschema is not telling me where it came from, I could try to match the subschema, but that would require deep compare and doesn't guarantee me what I search for. What I would expect is something like the path, but related to schema. Referring to my example it would be:["property", "foo"], ["allOf"] and ["allOf","property", "foo"].

awwright commented 2 years ago

@ri0ter Ok, that makes sense. Let's call this property "schemaPath" and have it work similar to "path".

The best you can do right now is you can use strict equality === to determine if the schema that produced the error is some schema that you have a reference to. For example, you could try:

const schema = {
    type: 'object',
    properties: {
      foo: { type: 'string', minLength: 2 },
      bar: { type: 'array' },
    },
    allOf: [
      {
        properties: {
          foo: {
            minLength: 1,
          },
        },
      }
    ]
};
const result = validate({
  foo: '',
}, schema);

result.errors[0].schema === schema.properties.foo; // true
result.errors[0].schema === schema.allOf[0].properties.foo; // false