David Froger
David Froger

Reputation: 665

jsonschema: Abstract Data Type and correct error message

I'm using the jsonschema Python library like this:

import jsonschema

schema = {
    "type": "object",
    "oneOf": [
        {
            "type": "object",
            "additionalProperties": False,
            "required": ["key"],
            "properties": {"key": {"enum": ["foo"], "type": "string"}},
        },
        {
            "type": "object",
            "additionalProperties": False,
            "required": ["key", "baritem"],
            "properties": {
                "key": {"enum": ["bar"], "type": "string"},
                "baritem": {"type": "string"},
            },
        },
    ],
}

I can validate correct data:

jsonschema.validate({"key": "bar", "baritem": "ok"}, schema)

But if a property is missing, if fails (as expected), but with a strange error message:

jsonschema.validate({"key": "bar"}, schema)
Traceback (most recent call last):
  File "valid.py", line 29, in <module>
    jsonschema.validate({"key": "bar"}, schema)
  File "/home/david/.pyenv/versions/3.7.11/lib/python3.7/site-packages/jsonschema/validators.py", line 934, in validate
    raise error
jsonschema.exceptions.ValidationError: 'bar' is not one of ['foo']

Failed validating 'enum' in schema[0]['properties']['key']:
    {'enum': ['foo'], 'type': 'string'}

On instance['key']:
    'bar'

My first question is: Is it the right way to defined the JSON schema, especially the part defined the key with an enum?

My second question is: Is there a way to define properly Abstract Data Type like this with jsonschema, ie to tell jsonschema to choose the object listed in oneOf based on the key property, and to validate the rest of the properties based on this object?

Upvotes: 0

Views: 61

Answers (2)

Ether
Ether

Reputation: 53966

You can choose which subschema to apply based on the values of other properties with if/then/else, as well as dependentSchemas: https://json-schema.org/understanding-json-schema/reference/conditionals.html

Upvotes: 1

David Froger
David Froger

Reputation: 665

For now, my solution will be to choose the specific schema to use by myself:

import jsonschema
from jsonschema.exceptions import ValidationError

schema_foo = {
    "type": "object",
    "additionalProperties": False,
    "required": ["key"],
    "properties": {"key": {"enum": ["foo"], "type": "string"}},
}

schema_bar = {
    "type": "object",
    "additionalProperties": False,
    "required": ["key", "baritem"],
    "properties": {
        "key": {"enum": ["bar"], "type": "string"},
        "baritem": {"type": "string"},
    },
}

schema = {
    "type": "object",
    "oneOf": [
        schema_foo,
        schema_bar,
    ],
}

schema_by_key = {"foo": schema_foo, "bar": schema_bar}

data = {"key": "bar"}

try:
    key = data["key"]
except KeyError:
    raise ValidationError("key is missing")

try:
    specific_schema = schema_by_key[key]
except KeyError:
    raise ValidationError("key is invalid")

jsonschema.validate(data, specific_schema)

So error is correctly reported:

Traceback (most recent call last):
  File "valid.py", line 43, in <module>
    jsonschema.validate(data, specific_schema)
  File "/home/david/.pyenv/versions/3.7.11/lib/python3.7/site-packages/jsonschema/validators.py", line 934, in validate
    raise error
jsonschema.exceptions.ValidationError: 'baritem' is a required property

Failed validating 'required' in schema:
    {'additionalProperties': False,
     'properties': {'baritem': {'type': 'string'},
                    'key': {'enum': ['bar'], 'type': 'string'}},
     'required': ['key', 'baritem'],
     'type': 'object'}

On instance:
    {'key': 'bar'}

Upvotes: 0

Related Questions