Search code examples
jsonschemajson-schema-validatorpython-jsonschema

How to extent an object with 1 parameter in json-schema


I wrote one JSON schema before, but now, as I am trying to make it a bit more advanced I get stuck.

(I am open to 'good practice' tips in the comments)

(Is the $id optional? should I remove it for simplicity in the example code?)

Goal:

I am trying to make a schema with an object definition (example_obj) that is recursively used. This object may only have 1 argument (or or and or value). But in the root of the json, I want to add 1 additional property.

json-schema

{
  "definitions": {
    "example_obj": {
      "$id": "#/definitions/example_obj",
      "type": "object",
      "maxProperties": 1,
      "properties": {
        "or": {
          "$id": "#/definitions/example_obj/properties/or",
          "type": "array",
          "items": {
            "$id": "#/definitions/example_obj/properties/or/items",
            "$ref": "#/definitions/example_obj"
          }
        },
        "and": {
          "$id": "#/definitions/example_obj/properties/and",
          "type": "array",
          "items": {
            "$id": "#/definitions/example_obj/properties/and/items",
            "$ref": "#/definitions/example_obj"
          }
        },
        "value": {
          "$id": "#/definitions/example_obj/properties/value",
          "type": "string"
        }
      }
    }
  },
  "type": "object",
  "title": "The Root Schema",
  "required": ["filter_version"],
  "allOf": [
    {
      "$ref": "#/definitions/example_obj"
    },
    {
      "properties": {
        "filter_version": {
          "$id": "#/properties/filter_version",
          "type": "string",
          "pattern": "^([0-9]+\\.[0-9]+)$"
        }
      }
    }
  ]
}

json which I want to pass validation:

{
  "filter_version": "1.0",
  "or": [
    {
      "and": [
        {
          "value": "subject"
        }
      ]
    },
    {
      "or": [
        {
          "value": "another subject"
        }
      ]
    }
  ]
}

Issue:

When I try to extend example_obj for the root definition it seems to fail because the example_obj object does not allow more then 1 property by design.

In other words, it appears that every check for the number of argument that I add to example_obj is also performed on the additional property (i.e. filter_version).

Does anyone know where to place this check for 'exactly 1 argument' so that it is not evaluated on the root object?

Attempts:

I tried working with different ways of determining the requirements of example_obj, but with no success. Like with replacing "maxProperties": 1 with:

"oneOf": [
  {
    "required": [
      "or"
    ]
  },
  {
    "required": [
      "and"
    ]
  },
  {
    "required": [
      "where"
    ]
  },
  {
    "required": [
      "where not"
    ]
  }
],

Thanks in advance for any help!!

Checking my schema with the online schema validator.

(In the end I need to validate it in Python, in case it matters)


Solution

  • You can use oneOf instead of maxProperties to get around this.

    {
      "type": "object",
      "properties": {
        "filter_version": {
          "type": "string",
          "pattern": "^([0-9]+\\.[0-9]+)$"
        }
      },
      "required": ["filter_version"],
      "allOf": [{ "$ref": "#/definitions/example_obj" }],
      "definitions": {
        "example_obj": {
          "type": "object",
          "properties": {
            "or": { "$ref": "#/definitions/example-obj-array" },
            "and": { "$ref": "#/definitions/example-obj-array" },
            "value": { "type": "string" }
          },
          "oneOf": [
            { "required": ["or"] },
            { "required": ["and"] },
            { "required": ["value"] }
          ]
        },
        "example-obj-array": {
          "type": "array",
          "items": { "$ref": "#/definitions/example_obj" }
        }
      }
    }
    

    P.S. You are using $id wrong. I know there is a tool out there that generates schemas like this and causes this confusion. The way $id is used here is a no-op. It doesn't hurt, but it doesn't do anything other than bloating your schema.