18

Let's say I have the following JSON Schema

{
 "name":"Product",
 "type":"object",
 "properties":{
   "id":{
     "type":"number",
     "required":true
   },
   "name":{
     "description":"Name of the product",
     "required":true
   },
   "price":{
     "required":true,
     "type": "number",
     "minimum":0,
     "required":true
   },
   "tags":{
     "type":"array",
     "items":{
       "type":"any"
     }
   }
 }
}

But, instead of tags being an array, I'd like it to be part of the root schema. So you could specify any property, but I give special attention to "id", "name" and "price" Which of the following would be the correct way of doing it, and which ones are completely wrong?

{
 "name":"Product",
 "type":"object",
 "properties":{
   "id":{
     "type":"number",
     "required":true
   },
   "name":{
     "description":"Name of the product",
     "required":true
   },
   "price":{
     "required":true,
     "type": "number",
     "minimum":0,
     "required":true
   }
 },
 "additionalProperties": {
     "type":"any"
 }
}

{
 "name":"Product",
 "type":"object",
 "properties":{
   "id":{
     "type":"number",
     "required":true
   },
   "name":{
     "description":"Name of the product",
     "required":true
   },
   "price":{
     "required":true,
     "type": "number",
     "minimum":0,
     "required":true
   }
 },
 "extends": {
     "type":"any"
 }
}

{
 "name":"Product",
 "type":["object","any"],
 "properties":{
   "id":{
     "type":"number",
     "required":true
   },
   "name":{
     "description":"Name of the product",
     "required":true
   },
   "price":{
     "required":true,
     "type": "number",
     "minimum":0,
     "required":true
   }
 }
}

I can come up with a few more (such as inverting roles of "any" and "object"), but they are all derivative of these three examples.

Bernardo Cunha
  • 443
  • 1
  • 5
  • 10

1 Answers1

37

[disclaimer: author of the next JSON Schema validation spec here]

OK, it is unclear what you ask, see below, but one of your examples clearly does not do what you want, this is the one where you write:

{ "type": [ "object", "any" ] }

This is equivalent to an empty schema, and as such validates each and every instance.

One way I read your question is that you want your JSON data to be either a tag array or an object with at least members named id, name and price. Since you seem to be using draft v3, you only have one solution:

{
    "type": [
        {
            "description": "schema for tags array here",
        },
        {
            "description": "schema for the base object here"
        }
    ]
}

This construct means that the instance must obey at least one schema inside type (and you can mix it with primitive types as well).

However: the current draft now being v4, you should now write:

{
    "anyOf": [
        {
            "description": "schema for tags array here",
        },
        {
            "description": "schema for the base object here"
        }
    ]
}

Note that not all implementations support draft v4, or the construct for type above. In fact, very few do. See below for a link to an online schema validator which supports both.

Another way that I read your question is that you want to allow properties other than id, name and price to be whatever they like. This is then quite simple. Just don't define a schema for tags in properties:

{
    "type": "object",
    "required": [ "id", "name", "price" ]
    "properties": {
        "id": {
            "type": "number"
        },
        "name": {
            "description": "Name of the product"
        },
        "price": {
            "type": "number",
            "minimum": 0
        }
    }
}

Since you don't specify additionalProperties as being false, the object instance can have any number of additional members, and these members can be anything.

Link to an online validator which can test your schemas: here

fge
  • 119,121
  • 33
  • 254
  • 329
  • 1
    This was very helpful, I didn't realize that you could define multiple possible type values. (Yeah, newb at json schemas here.) – Turnsole Jan 29 '13 at 23:50
  • And, errr, what do you want to do, then? You still did not really tell ;) – fge Jan 30 '13 at 01:10
  • I didn't really say anything, it wasn't my question. I just happened to show up thanks to Google. If you're curious, though, I was trying to handle the case when the API I'm getting JSON from sends me an object some of the time and an integer other times, but I still want one of those two and not "any". – Turnsole Jan 30 '13 at 07:02
  • You can post a message to the JSON Schema google group, they'll help you make your schema ;) – fge Jan 30 '13 at 07:41
  • Sorry being late on this, but you have answered my question and then some. Brilliant. Thanks a ton. :) – Bernardo Cunha Feb 28 '13 at 15:43
  • @fge what if my schema element can either be an array or null? If I try writing null, it gives me an error: "found null, expected one of [array, string]" – amey91 Dec 29 '14 at 19:45
  • 1
    @amey91 a null value in JSON Schema is `"type": "null"`, or, if in an enum, the value null: `{ "enum": [ null ] }` – fge Dec 29 '14 at 21:35
  • @fge TY! I was using null without quotation marks and that was causing the error – amey91 Dec 30 '14 at 00:59