Format validation
In this example we register and enable validators for the ipv4
and ipv6
formats.
import ipaddress
import pprint
from jschon import JSON, JSONSchema, create_catalog
from jschon.vocabulary.format import format_validator
# register an 'ipv4' format validator
@format_validator('ipv4')
def validate_ipv4(value: str) -> None:
if isinstance(value, str):
ipaddress.IPv4Address(value) # raises ValueError for an invalid IPv4 address
# register an 'ipv6' format validator
@format_validator('ipv6')
def validate_ipv6(value: str) -> None:
if isinstance(value, str):
ipaddress.IPv6Address(value) # raises ValueError for an invalid IPv6 address
# initialize the catalog, with JSON Schema 2020-12 vocabulary support
catalog = create_catalog('2020-12')
# enable validation with the 'ipv4' and 'ipv6' format validators
catalog.enable_formats('ipv4', 'ipv6')
# create a schema for validating an array of IP addresses
schema = JSONSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schema",
"type": "array",
"items": {
"type": "string",
"anyOf": [
{"format": "ipv4"},
{"format": "ipv6"}
]
}
})
# evaluate a valid array
valid_result = schema.evaluate(JSON(['127.0.0.1', '::1']))
# evaluate an invalid array
invalid_result = schema.evaluate(JSON(['127.0.1', '::1']))
# print output for the valid case
print('Valid case output:')
pprint.pp(valid_result.output('basic'))
# print output for the invalid case
print('Invalid case output:')
pprint.pp(invalid_result.output('basic'))
The script produces the following output:
Valid case output:
{'valid': True,
'annotations': [{'instanceLocation': '',
'keywordLocation': '/items',
'absoluteKeywordLocation': 'https://example.com/schema#/items',
'annotation': True},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/0/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/0/format',
'annotation': 'ipv4'},
{'instanceLocation': '/1',
'keywordLocation': '/items/anyOf/1/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/1/format',
'annotation': 'ipv6'}]}
Invalid case output:
{'valid': False,
'errors': [{'instanceLocation': '',
'keywordLocation': '/items',
'absoluteKeywordLocation': 'https://example.com/schema#/items',
'error': [0]},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf',
'error': 'The instance must be valid against at least one '
'subschema'},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/0/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/0/format',
'error': 'The instance is invalid against the "ipv4" format: '
"Expected 4 octets in '127.0.1'"},
{'instanceLocation': '/0',
'keywordLocation': '/items/anyOf/1/format',
'absoluteKeywordLocation': 'https://example.com/schema#/items/anyOf/1/format',
'error': 'The instance is invalid against the "ipv6" format: At '
"least 3 parts expected in '127.0.1'"}]}