0

I'm trying to find a way to alter schema validation to find most appropriate schema for a given object. Let's say we have a schema:

{
  "oneOf": [
    {
      "$ref": "#/definitions/a"
    },
    {
      "$ref": "#/definitions/b"
    }
  ],
  "definitions": {
    "a": {
      "type": "object",
      "properties": {
        "prop1": {
          "enum": ["x"]
        }
      },
      "required": ["prop1"]
    },
    "b": {
      "type": "object",
      "properties": {
        "prop1": {
          "enum": ["y"]
        },
        "prop2": {
          "type": "string"
        }
      },
      "required": ["prop1", "prop2"]
    }
  }
}

Now, if I have an object { "prop1": "y" }, I want it to be resolved as of #/definitions/b type, even if it's not really valid for this scheme. That is, I want to use just prop1 property for resolving.

I wonder if there is a way to do it using AJV custom keywords, without rebuilding the schema itself? In particular, if schema is not valid for an object, is it possible to use custom keywords to override it and make it valid?

1 Answers1

1

If the objective is to only report errors from the correct schema you can use either "switch" (with v5 option, it is moved to ajv-keywords from version 5.0.0) or "if/then/else" (it is recommended as it is likely to be added in JSON Schema draft 7):

{
  "id": "schema",
  "if": { "properties": { "prop1": { "const": "x" } } },
  "then": { "$ref": "#/definitions/a" },
  "else": { "$ref": "#/definitions/b" }
}

If you need to know which schema was used for validation you can use a custom keyword to make a note of it:

{
  "id": "schema",
  "if": { "properties": { "prop1": { "const": "x" } } },
  "then": {
    "allOf": [
     { "schemaUsed": "schema#/definitions/a" },
     { "$ref": "#/definitions/a" }
    ]
  },
  "else": {
    "allOf": [
     { "schemaUsed": "schema#/definitions/b" },
     { "$ref": "#/definitions/b" }
    ]
  }
}

The keyword should be defined to store schema ID during validation in some variable so that after validation you could see which one was used.

If you need to get actual schema you can do:

var validate = ajv.getSchema('schema#/definitions/a'); // validating function
var schema = validate.schema; // schema as JSON
esp
  • 7,314
  • 6
  • 49
  • 79
  • It will not help, I'm afraid. The objective in general is to build UI for editing JSON objects according to schema. So if there is `oneOf` in schema, I need to know what variant should I choose. The problem is that an object may be currently invalid due to incompleteness (the required field is absent, for example, or a nested property is invalid in a same way, or something else), so I need to find a way to trick AJV somehow (I'm using one AJV instance for resolving appropriate schema and other for actual validation) so it would find the right schema. – Alexander Kuznetsov Jan 04 '17 at 16:33
  • Ajv validates data against the schema. It doesn't really generate or manipulates schemas in any way - it takes schema (JSON) and creates a validating function (code), there is no "final" schema or anything like this. You can use custom keywords together with if/then/else to let you know which schema is being validated, in "if" branch or in "else" branch, or you can simply derive this information from errors (if the validation fails). – esp Jan 04 '17 at 18:36
  • See the changes – esp Jan 04 '17 at 18:45
  • I see. This wouldn't help me to find the schema though if object is not valid, so I guess the best option for me is to write my own resolver (which I already do anyway, just wanted to know if AJV could help me somehow with that). Thank you for a quick response! – Alexander Kuznetsov Jan 04 '17 at 22:48
  • Yes, it will - see the updated answer. Once you have the reference recorded by the custom keyword, your schema object is at `ajv.getSchema('schema#/definitions/a').schema`, regardless whether validation has failed or succeeded. You can even make a custom keyword that would use a current schema path, so you don't have to repeat it in the schema and put it inside definitions instead of as siblings to $ref. – esp Jan 04 '17 at 23:33