# Data : JSON Schema
\[ [specs](https://json-schema.org/specification) | [guide](https://json-schema.org/understanding-json-schema) ]
JSON-based format to define the structure of JSON data.
#### Basics
> "JSON Schema does not have the full verification capabilities of a relational database. ... For example, you cannot ensure that the values in a particular field also appear as the primary key in another file (foreign key constraint). In general, JSON Schema can look at one object (or file of similar objects) but not across multiple datasets."
> — [Chuck Connell](https://towardsdatascience.com/json-schema-integrity-checking-for-nosql-data-b1255f5ea17d)
Media types: `application/schema+json`, `application/schema-instance+json`
###### Dialects
JSON Schema "dialects" are compatible with the core but may:
- add keywords
- remove keywords
- modify behavior of keywords
The default dialect is the [2020-12 draft](https://json-schema.org/draft/2020-12/schema).
###### Schemas and Subschemas
Schemas validate a value and are expressed as a JSON object or boolean.
> [!info]
> `{}` -> empty schema, matches all values | `true` → matches all values | `false` → matches none
Schemas are recursive structures. A schema appearing within a schema document is a **subschema**. In this document, **schemas** will refer to both, and **root schemas** will refer to whole documents.
Root schemas *may* (and *should*) specify the dialect they conform to. Otherwise, validators will assume some default.
```JSON
"$schema": "https://json-schema.org/draft/2020-12/schema"
```
###### IDs
All schemas *may* (and root schemas *should*) contain a URI id which can then be referenced both within the same document and in external documents.
```JSON
"$id": "https://yourdomain.com/schemas/myschema.json"
```
#### Keywords
###### Universal
```JSON
type : <type> -or- [ type1, ... ] # array, boolean, integer, null, number, object, string
# Annotations (not strictly used for validation)
title : <str>
description : <str>
default : <*> # used for docs, not to fill in missing values
examples : [ ... ] # values that validate against schema
readOnly : true
writeOnly : true
deprecated : true
# Misc
$comment : <str>
enum : [ ... ] # contains 1+ unique values
const : <*> # restrict to single value
# Defs & Refs
$defs : { # place to define named subschemas
<name> : <schema>
}
$ref : <uri> # external root schema
$ref : #<json-pointer> # local subschema (JSON Pointer example: /foo/0/bar)
$ref : <uri>#<json-pointer> # external subschema (not recommended)
# Composition
allOf : [ <schema1>, ... ] # must be valid against all of the subschemas
anyOf : [ <schema1>, ... ] # must be valid against any of the subschemas
oneOf : [ <schema1>, ... ] # must be valid against exactly one of the subschemas
not : <schema> # must not be valid against the given schema
```
###### Numbers
```JSON
multipleOf : <posnum>
minimum : <num>
maximum : <num>
exclusiveMinimum : <num>
exclusiveMaximum : <num>
```
###### Strings
```JSON
format : <format> # validators may treat this as either annotation or assertion
# see list of built-in formats below
minLength : <posint>
maxLength : <posint>
pattern : "^...$ # JS regex syntax
```
###### Arrays
```JSON
# List Validation: sequence of arbitrary length, each item matches the same schema
items : <schema> # applied to every item in array
# Tuple Validation: sequence of fixed length, each item may have a different schema
items : false # disallow items other than those in prefixItems
prefixItems : [ <schema1>, ... ] # applied positionally
contains : <schema> # must validate against at least one item
minContains : <posint> # affect quantity needed for "contains"
maxContains : <posint>
minItems : <posint>
maxItems : <posint>
uniqueItems : true
```
###### Objects
```JSON
# By default:
# - properties listed here are not required to be present
# - properties not listed here are skipped during validation
properties : {
<prop_name> : <schema>
}
patternProperties : {
"^...
quot; : <schema>
}
# applied to properties that aren't handled above
# only aware of locally-declared properties, not external definitions
additionalProperties : <schema>
additionalProperties : false # disallow additional properties
# new alternative to additionalProperties - aware of properties in external definitions
unevaluatedProperties : <schema>
unevaluatedProperties : false
required : [ <prop_name1>, ... ]
# validate property names against schema, irrespective of their values
propertyNames : <schema>
minProperties : <posint>
maxProperties : <posint>
```
#### Formats
###### Built-in
```JSON
regex : see ECMA 262
# Dates & Times (RFC 3339 / ISO8601)
date-time : ex: 2018-11-13T20:20:39+00:00
time : ex: 20:20:39+00:00
date : ex: 2018-11-13
duration : see ISO 8601 ABNF for “duration”; ex: "P3D" -> 3 days
# Email Addresses
email : see RFC 5321, section 4.1.2
idn-email : internationalized form; see RFC 6531
# Hostnames
hostname : internet host name; see RFC 1123 section 2.1
idn-hostname : internationalized form; see RFC 5890 section 2.3.2.3
# IP Addresses
ipv4 : see dotted-quad ABNF syntax in RFC 2673 section 3.2
ipv6 : see RFC 2373 section 2.2
# Resource Identifiers
uuid : see RFC 4122; ex: 3e4666bf-d5e5-4aa7-b8ce-cefe41c7568a
uri : for absolute paths; see RFC 3986
uri-reference : for relative paths; see RFC 3986 section 4.1
iri : internationalized uri; see RFC 3987
iri-reference : internationalized uri-reference; see RFC 3987
# JSON Pointer
json-pointer : see RFC 6901; ex: "/foo/bar" ("#/foo/bar" should use uri-reference)
relative-json-pointer : relative JSON pointer
```
## Python
#### fastjsonschema
\[ [pypi](https://pypi.org/project/fastjsonschema/) | [src](https://github.com/horejsek/python-fastjsonschema/) | [docs](https://horejsek.github.io/python-fastjsonschema/) ]
```python
from fastjsonschema import compile, compile_to_code, validate
from fastjsonschema import JsonSchemaException, JsonSchemaDefinitionException
JsonSchemaException # raised by validation function
# properties: message, name, path, rule
JsonSchemaDefinitionException # raised by compile()
validate( definition, data ) # for convenience; slower than compiling first
compile( definition ) # returns validation function that accepts data
my_validator = compile( dict( type="string" ) )
my_validator( "hello" )
```