6

Say I have a JSON schema that allows for an object like so:

...
  "assetMetadata": {
    "type": "object",
    "additionalProperties": false,
    "properties": { ... }
  }
...

So say I want to change this to allow either that same object OR an array of that particular object. Here is accepting just an array:

...
"assetMetadata": {
  "type": "array",
  "description": "...",
  "items": {
    "type": "object",
    "additionalProperties": false,
    "properties": {...}
}
...

The properties are the same (it's the same object, just the option for multiple instead of just one).

Interestingly enough in the project I'm working on, the unmarshaller can already handle both (it turns the single object into a sequence of size 1), so it's purely the validation that's preventing me from going forward. We want to maintain comparability with the existing API, which is the reason I can't just require an array now.

djsumdog
  • 2,560
  • 1
  • 29
  • 55

2 Answers2

14

You can achieve this using the anyOf keyword and definitions/$ref to avoid duplication.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "assetMetadata": {
      "anyOf": [
        { "$ref": "#/definitions/assetMetaData" },
        {
          "type": "array",
          "description": "...",
          "items": { "$ref": "#/definitions/assetMetaData" }
        }
      ]
    }
  },
  "definitions": {
    "assetMetadata": {
      "type": "object",
      "additionalProperties": false,
      "properties": { ... }
    }
  }
}
Befedo
  • 139
  • 2
  • 11
Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53
  • Is it possible to use "oneOf" instead of "anyOf" in this case? – faniva Aug 02 '22 at 15:51
  • `oneOf` would produce the same result, but it would do it in a less efficient way. `oneOf` means one and only one of the schema can pass validation. These two options are mutually exclusive, meaning that if one schema passes we know the other will always fail (a value can't be an object and an array at the same time). So, if the validator checks the first case and it passes, `anyOf` can stop processing while `oneOf` would have to check that the second case fails. Using `anyOf` allows the validator to skip the redundant check. – Jason Desrosiers Aug 03 '22 at 17:22
0

The accepted answer was not working for me in the JSON schema validator.

The arrays were not being accepted.

I made some tweaks and changes to make it work, here is an example schema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "anyOf": [
    {
      "$ref": "#/definitions/commentObject"
    },
    {
      "type": "array",
      "description": "Array of Comment objects",
      "items": {
        "$ref": "#/definitions/commentObject"
      }
    }
  ],
  "definitions": {
    "commentObject": {
      "properties": {
        "number": {
          "type": "integer",
          "minLength": 0,
          "maxLength": 256
        },
        "comment": {
          "type": "string",
          "minLength": 0,
          "maxLength": 256
        }
      },
      "required": [
        "number",
        "comment"
      ],
      "type": "object"
    }
  }
}

Object used to test the validation:

{
  "number": 47,
  "comment": "This is a comment",
}

Arrays of objects used to test the validation:

[
  {
    "number": 47,
    "comment": "This is a comment"
  },
  {
    "number": 11,
    "comment": "This is other comment"
  }
]

JSON Schema Validator for object

JSON Schema Validator for array (of the same objects)

David
  • 356
  • 4
  • 6