JSON Schema - specify field is required based on value of another field

40,411

Solution 1

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".

Solution 2

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.

Solution 3

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.

Solution 4

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.

Share:
40,411
pospi
Author by

pospi

Full-stack Holochain, blockchain &amp; web developer with deep knowledge of everything from writing smart contracts to configuring database clusters to implementing highly responsive layouts. Currently building things with Holochain, Rust, Node, Webpack, PostCSS, React, GraphQL, Redux, Rxjs &amp; similar stuff; but who knows what will be happening in the JavaScript ecosystem next week.

Updated on July 09, 2022

Comments

  • pospi
    pospi almost 2 years

    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"
            }
        }
    }
    
  • pospi
    pospi about 12 years
    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.
  • cloudfeet
    cloudfeet over 11 years
    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.
  • Relequestual
    Relequestual over 9 years
    What about in version 4 of the specification?
  • cloudfeet
    cloudfeet over 9 years
    I'll add something to the answer to clarify v4 alternatives
  • Relequestual
    Relequestual over 9 years
    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
  • cloudfeet
    cloudfeet over 9 years
    Oh, right, so you're looking to avoid duplication? You could try something like 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
    cloudfeet over 9 years
    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.
  • Relequestual
    Relequestual over 9 years
    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
    Relequestual over 9 years
  • Relequestual
    Relequestual over 9 years
    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.
  • ppalacios
    ppalacios over 7 years
    @Relequestual if you are still looking for an answer, check mines ;)
  • Nilesh
    Nilesh over 7 years
    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.
  • ppalacios
    ppalacios about 7 years
    @Nilesh sorry, what do you want to achieve?
  • Sisyphus
    Sisyphus over 6 years
    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.
  • Mike
    Mike almost 4 years
    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.
  • Sebastian Slutzky
    Sebastian Slutzky almost 3 years
    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?