49

Wondering if this is possible with schema draft 03. I've gotten dependencies working elsewhere, I think there is possibly just some creative use of them required in order to use them for specifying the required property of some field.

My current best attempt (which doesn't work) should give you some idea of what I'm after. I want a value required by default, and optional when another field has a particular value.

{
    "description"   : "An address...",
    "type" : "object",
    "properties" : {
        "postcode": {
            "type" : "string",
            // postcode should be required by default
            "required" : true,      
            // postcode shouldn't be required if the country is new zealand 
            "dependencies" : {
                "country" : {
                    "enum" : ["NZ", "NZL", "NEW ZEALAND"]
                },
                "postcode" : {
                    "required" : false      
                }
            }
        },
        "country": {
            "type" : "string",
            "enum" : [
                // various country codes and names...
            ],
            "default" : "AUS"
        }
    }
}
jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
pospi
  • 3,540
  • 3
  • 27
  • 26

4 Answers4

29

This is definitely possible with version 3 of the draft. Since you have a complete list of allowed countries, then you could do something like this:

{
    "type": [
        {
            "title": "New Zealand (no postcode)",
            "type": "object",
            "properties": {
                "country": {"enum": ["NZ", "NZL", "NEW ZEALAND"]}
            }
        },
        {
            "title": "Other countries (require postcode)",
            "type": "object",
            "properties": {
                "country": {"enum": [<all the other countries>]},
                "postcode": {"required": true}
            }
        }
    ],
    "properties": {
        "country": {
            "type" : "string",
            "default" : "AUS"
        },
        "postcode": {
            "type" : "string"
        }
    }
}

So you actually define two sub-types for your schema, one for countries that require a postcode, and one for countries that do not.

EDIT - the v4 equivalent is extremely similar. Simply rename the top-level "type" array to "oneOf".

CubeJockey
  • 2,209
  • 8
  • 24
  • 31
cloudfeet
  • 12,156
  • 1
  • 56
  • 57
  • 6
    It's worth noting that in version 4, putting schemas in the `type` keyword will be forbidden. You would instead probably want to use `allOf` or `oneOf`. – cloudfeet Oct 18 '12 at 15:38
  • What about in version 4 of the specification? – Relequestual Oct 06 '14 at 12:57
  • 1
    I'll add something to the answer to clarify v4 alternatives – cloudfeet Oct 06 '14 at 13:30
  • 2
    I mean specifically, is there a better / different way to achive the above with v4? I have a 100 line json schema so far... I don't want to double it for just one conditional require – Relequestual Oct 06 '14 at 14:43
  • 1
    Oh, right, so you're looking to avoid duplication? You could try something like [json-schema-compatibility](https://www.npmjs.org/package/json-schema-compatibility), which normalises schemas to v4 syntax. You can use it to convert v3->v4, or use it on-the-fly to use v3 schemas with v4 tools. – cloudfeet Oct 06 '14 at 15:20
  • However, no, there is no syntax for this that works for both v3 and v4. It is highly recommended to stop using v3, and move over to v4 completely - any tool that is still stuck on v3 probably isn't the most actively maintained. – cloudfeet Oct 06 '14 at 15:22
  • The only trouble is, I'm using perl, where there is only ONE library which does json-schema... which the author said he has no intension of updating till the spec is "released", and I've just volenteered to update it to v4 (although I need to get this code working with v3 before I can commit any time to do that). – Relequestual Oct 06 '14 at 15:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62527/discussion-between-relequestual-and-cloudfeet). – Relequestual Oct 06 '14 at 15:33
  • 1
    @Relequestual if you are still looking for an answer, check mines ;) – Pablo Oct 27 '16 at 19:45
17

If anybody is looking for a solution for draft 4 you can use dependencies keyword together with a enum keyword:

{
    "type": "object",
    "properties": {
        "play": {
            "type": "boolean"
        },
        "play-options": {
            "type": "string"
        }
    },
    "dependencies": {
        "play-options": {
            "properties": {
                "play": {
                     "enum": [true]
                }
            }
        }
    }
}

In this wayplay-options will always require play value to be true.

Pablo
  • 1,311
  • 9
  • 20
  • Yeah, it works. Thanks. It would be helpful if you tell way to invalidate ```{ "play": true } ```. That is, play-options is required if condition satisfies. – Nilesh Jan 25 '17 at 05:27
  • @Nilesh sorry, what do you want to achieve? – Pablo Jan 26 '17 at 14:01
  • 6
    I don't think this answers the question. The dependency in the answer means when `play-options` exists, `play` must be `true`. But when `play` is `true`, `play-options` don't have to exists. – Sisyphus Oct 21 '17 at 13:35
7

In the latest schema you can use the oneOf conditional to do this.

{
    "description"   : "An address...",
    "type" : "object",
    "properties" : {
        "postcode": {
            "type" : "string"
        },
        "country": {
            "type" : "string",
            "enum" : [
                // various country codes and names...
            ],
            "default" : "AUS"
        }
    },
    "oneOf": [
        {
          "properties": {
            "country": { "enum" : ["NZ", "NZL", "NEW ZEALAND"] }
          }
        },
        { "required": ["postcode"] } 
      ]
}

The oneOf condition requires that one of the conditions in the array is true.

Mike
  • 10,297
  • 2
  • 21
  • 21
  • Updated location of `oneOf`. Good catch! I think the mention of `oneOf` in the accepted answer is a little bit buried (I didn't see it when I was searching for an answer to this question), so figured I would make it more obvious. – Mike May 20 '20 at 01:28
  • thanks Mike . I've a similiar requirement, but my "Country" field needs to be free text, and require postcode only if country="NZ". Is that possible? – Sebastian Slutzky Jul 20 '21 at 13:59
2

I just looked over the 03 version of the spec and I don't think what you are describing is possible. It's definitely not "Simple Dependency" and the description of "Schema Dependency" doesn't mention any way to consider the value of the property.

It sounds like what you need is "Conditional Schema Dependency".

There's some discussion of what's possible with Simple and Schema dependencies here: http://groups.google.com/group/json-schema/msg/8145690ebb93963b

You might ask that group if there are plans to support conditional dependencies.

Chris Sears
  • 6,502
  • 5
  • 32
  • 35
  • brilliant, thanks for the link. It seems like JSON Schema is pretty much in its infancy at the moment, finding any kind of documentation is hard! >< I think what is really required is a way for dependencies to manipulate the original properties of the schema they are defined within - this would allow overriding default values & requirements via dependencies as well as numerous other possible tricks. – pospi Feb 03 '12 at 00:41
  • The link provided in the answer contains a very valuable and practicale example! It's a shame there isn't better documentation / more practical examples for each part of the spec. – Relequestual Oct 07 '14 at 08:51