Search code examples
jsonjsonschemajson-schema-validatorajv

Specifying an object should be empty if another object has properties in JSON schema


I have data that comes back from GraphQL, I'd like to verify that data with JSON schema before manipulating it.

There might be a better way of doing this in graphQL than I currently am, but the data that comes back can be of two types with the same properties:

e.g. a simplified version of the data

obj: {
  audio: {
    artists: []
  },
  video: {}
}

or

obj: {
  audio: {},
  video: {
    artists: []
  }
}

So validity would be:

  • an object with both a audio and video property
  • an object with audio as an object with a property artists and an empty property video object
  • an object with video as an object with a property artists and an empty property audio object
  • neither audio or video should be empty together
  • neither audio or video should have properties together

I've built a simplified schema that looks like this:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "file://schemas/simple.schema.json",
  "title": "simplified data",
  "description": "simple",
  "type": "object",
  "properties": {
    "audio": {
      "type": "object"
    },
    "video": {
      "type": "object"
    }
  },
  "oneOf": [
    {
      "audio": {
        "type": "object",
        "properties": {
          "artists": {
            "type": "array"
          }
        }
      },
      "video": {
        "type": "object",
        "properties": {}
      }
    },
    {
      "audio": {
        "type": "object",
        "properties": {}
      },
      "video": {
        "type": "object",
        "properties": {
          "artists": {
            "type": "array"
          }
        }
      }
    }
  ]
}

but AJV doesn't seem to validate the data correctly when run against:

{
  "audio": {
    "artists": []
  },
  "video": {}
}

What might have I got wrong with my schema?


Solution

  • After an initial attempt, Jason pointed out a simpler solution...

    Using oneOf, you can specify that only one of the objects may have at least one property.

    You can test this here: https://jsonschema.dev/s/SSRaL

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "$id": "file://schemas/simple.schema.json",
      "properties": {
        "audio": {
          "type": [
            "object"
          ],
          "properties": {
            "artists": {
              "$comment": "whatever validation you want"
            }
          }
        },
        "video": {
          "type": [
            "object"
          ],
          "properties": {
            "artists": {
              "$comment": "whatever validation you want"
            }
          }
        }
      },
      "oneOf": [
        {
          "properties": {
            "video": {
              "minProperties": 1
            }
          }
        },
        {
          "properties": {
            "audio": {
              "minProperties": 1
            }
          }
        }
      ]
    }