Correct JSON Schema for an array of items of different type

51,497

Solution 1

I asked this same question on the JSON schema google group, and it was answered quickly. User fge asked that I post his response here:

Hello,

The current specification is draft v4, not draft v3. More specifically, the validation specification is here:

https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00

The web site is not up to date, I don't know why... I'll submit a pull request.

With draft v4 you can use this:

{
    "type": "array",
    "items": {
        "oneOf": [
            {"first": [ "schema", "here" ] }, 
            {"other": [ "schema": "here" ] }
        ]
    }  
}

For instance, this is a schema for an array where items can be either strings or integers (it can be written in a more simple way though):

{
    "type": "array",
    "items": {
        "oneOf": [
            {"type": "string"},
            {"type": "integer"}
        ]
    }
}

This is the correct answer. My corrected schema now includes:

"transactions" : {
    "type" : "array",
    "items" : {
        "oneOf" : [
            {
                "type" : "object",
                "properties" : {
                    "type" : {
                        "type" : "string",
                        "enum" : ["BUILD", "REASSIGN"]
                    }
                }
            },
            {
               "type" : "object",
               "properties" : {
                 "type" : {
                   "type" : "string",
                   "enum" : ["BREAK"]
                  }
               }
            }
        ]
    }
}

Solution 2

I've been looking into this for quite a while too. But haven't been able to find a working solution. It works fine if you have only one schema eg.

"transactions" : {
          "type" : "array",
          "items" : 
          {
            "type" : "object",
            "properties" : {
              "type" : {
                "type" : "string",
                "enum" : ["BREAK"]
              },
          }
}

Then you just skip the array brackets, and use an object. However if you want to do what you are doing, there seems to be no solid answer. This is the only thing that I've found so far: http://the-long-dark-tech-time.blogspot.se/2012/12/using-json-schema-with-array-of-mixed.html

Solution 3

For anyone stuck with the draft 3 schema. There is a "Type" keyword that is equivalent to the "anyOf" in draft 4:

So you can use

{
    "fooBar" : {
        "type" : "array",
        "items" : {
            "type" : [{
                    "type" : "object",
                    "properties" : {
                        "foo" : {                           
                            "type" : "string"
                        }
                    }
                }, {
                    "type" : "object",
                    "properties" : {
                        "bar" : {
                            "type" : "string"
                        }
                    }
                }
            ]
        }
    }
}

Solution 4

As a response to user Vdex: this is not equivalent, what you wrote means that array elements occur in this particular order within the array.

Subject to a correct implementation, if you use this schema validator.

With this schema:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "array",
  "items": [
    {
      "type": "boolean"
    },
    {
      "type": "number"
    },
    {
      "type": "string"
    }
  ]
}

This JSON will be validated:

[
  true,
  5,
  "a",
  "6",
  "a",
  5.2
]

But not this one:

[
  5,
  true,
  "a",
  "6",
  "a",
  5.2
]

Thus, the objective is totally different from keywords like "oneOf".

Solution 5

In my case, I want the first element in the array has a specific format, the remain elements have another format. This is my solution:

my_schema = {
    "type": "object",
    "properties": {
        "token": {"type": "string"},
        "service_id": {"type": "string"},
        "promo_code": {"type": "string"},
        "path": {
            "type": "array",
            "items": [
                {
                    "type": "object",
                    "properties": {
                        "address": {"type": "string"},
                        "lat": {"type": "number"},
                        "lng": {"type": "number"}
                    },
                    "required": ["address", "lat", "lng"]
                },
                {
                    "type": "object",
                    "properties": {
                        "address": {"type": "string"},
                        "lat": {"type": "number"},
                        "lng": {"type": "number"},
                        "district_id": {"type": "number"},
                        "ward_code": {"type": "number"},
                        "weight": {"type": "number"}
                    },
                    "required": ["address","lat", "lng","ward_code", 
                                 "district_id", "weight"]
                }
            ]
        }
    },
    "required": ["token", "service_id", "path"]
}

The above schema means that from the second element of the path, I required the district_id, the ward_code, the weight

Share:
51,497
deepwinter
Author by

deepwinter

Full Stack Mobile GIS Developer

Updated on December 03, 2020

Comments

  • deepwinter
    deepwinter over 3 years

    I have an unordered array of JSON items. According to the specification https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-03#section-5.5 the json schema below will only validate if the objects in the array appear IN THAT ORDER. I don't want to specify an order, just validate the objects within the array, regardless of order or number of objects. From the spec I can't seem to understand how this is done.

    "transactions" : {
        "type" : "array",
        "items" : [
            {
                "type" : "object",
                "properties" : {
                    "type" : {
                        "type" : "string",
                        "enum" : ["BUILD", "REASSIGN"]
                    }
                }
            },
            {
                "type" : "object",
                "properties" : {
                    "type" : {
                        "type" : "string",
                        "enum" : ["BREAK"]
                    }
                }
            }
        ]
    }