14

------------Josn schema-----------

{
    "type": "object",
    "properties": {
        "street_address": {
            "type": "string"
        },
        "city": {
            "type": "string"
        },
        "state": {
            "type": "string"
        }
    },
    "required": [
        "street_address"
    ],
    "additionalProperties": false
}

In above schema i want to create a choice between city and state. That is either city or state can come in json. So that below json would be invalid

{
    "street_address": "abc",
    "city": "anv",
    "state": "opi"
}

and below one should be valid one

{
    "street_address": "abc"
}

or

{
    "street_address": "abc",
    "city": "anv"
}

or

{
    "street_address": "abc",
    "state": "opi"
}

Can some one please help me to modify above schema to accomplish the goal.

Bill Sourour
  • 1,153
  • 1
  • 10
  • 20
javadev
  • 221
  • 1
  • 2
  • 10

4 Answers4

12

Use "oneOf" when only one of the alternatives should hold, and "anyOf" when at least one of the alternatives should hold.

You don't need to repeat common properties within oneOf. The shortest way to accomplish your goal would be:

{
    "type" : "object",
    "properties" : {
        "street_address" : {
            "type" : "string"
        },
        "city" : {
            "type" : "string"
        },
        "state" : {
            "type" : "string"
        }
    },
    "oneOf" : [{
            "required" : ["city"]
        }, {
            "required" : ["state"]
        }
    ],
    "required" : [
        "street_address"
    ],
    "additionalProperties" : false
}
jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
  • 2
    This schema violates the requirement that `{ "street_address": "abc" }` should be valid. – Rob Jun 06 '17 at 14:54
4

Here is a schema that satisfies all four conditions:

    {
        "type": "object",
        "properties": {
            "street_address": {
                "type": "string"
            },
            "city": {
                "type": "string"
            },
            "state": {
                "type": "string"
            }
        },
        "required": [
            "street_address"
        ],
        "anyOf": [{}, {
            "required": ["city"]
        }, {
            "required": ["state"]
        }],
        "not": {
            "required": ["city", "state"]
        },
        "additionalProperties": false
    }
Rob
  • 198
  • 7
4

I found the enum property useful for this use case.

Example:

schema = {
    "type": "array", 
    "items": {
        "enum": ["choice1", "choice2"]
    }
}

validate(
    instance=["choice1"], 
    schema=schema
)
# all good

validate(
    instance=["something-else"], 
    schema=schema
)
# ValidationError

Reference: https://json-schema.org/understanding-json-schema/reference/combining.html#combining-schemas

Hope it helps.

Martin Zugnoni
  • 1,439
  • 2
  • 14
  • 21
1

You would need to use "oneOf". Like so:

{
    "type": "object",
    "oneOf": [
        {
            "properties": {
                "street_address": {
                    "type": "string"
                },
                "city": {
                    "type": "string"
                }
            },
            "required": [
                "street_address"
            ]
        },
        {
            "properties": {
                "street_address": {
                    "type": "string"
                },
                "state": {
                    "type": "string"
                }
            },
            "required": [
                "street_address"
            ]
        }
    ]
}

You'll notice, it's a bit repetitive. Since, in your example, you only provide a "type" for each property, the repetition is not so bad. But if you have more complex properties, you could consider using deifinitions to define each property only once, at the top and then using $ref to reference the definition. Here's a good article on that.

Bill Sourour
  • 1,153
  • 1
  • 10
  • 20
  • 1
    This schema violates the requirement that `{ "street_address": "abc" }` should be valid, because both oneOf branches are matched. – Rob Jun 06 '17 at 15:02