JSON Schema Notes
Example
{
"first_name": "George",
"last_name": "Washington",
"birthday": "1732-02-22",
"address": {
"street_address": "3200 Mount Vernon Memorial Highway",
"city": "Mount Vernon",
"state": "Virginia",
"country": "United States"
}
}
schema:
{
"$schema": "http://json-schema.org/schema#",
"$id": "http://yourdomain.com/schemas/myschema.json",
"type": "object",
"properties": {
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"birthday": { "type": "string", "format": "date-time" },
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"country": { "type" : "string" }
}
}
}
}
Basics
Schema:
{ }
or
true
matches any well-formed JSON document!
false
matches no JSON document!
{ "type": "string" }
matches any string
{ "type": "number" }
matches any number
{ "type": ["number", "string"] }
matches any number OR string
{
"type": "string",
"minLength": 2,
"maxLength": 3
}
matches "ABC" but not "ABCD"
{
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
matches "555-1212" or "(888)555-1212" but not "(888)555-1212 ext. 532"
{ "type": "integer" }
{
"type" : "number",
"multipleOf" : 10
}
{
"type": "number",
"minimum": 0,
"exclusiveMaximum": 100
}
{ "type": "object" }
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
}
}
matches
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" }
or
{ "number": 1600, "street_name": "Pennsylvania" }
or
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }
leaving out properties is OK
additional properties are OK
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
},
"additionalProperties": false
}
will not match JSON with additional properties.
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
},
"additionalProperties": {"type": "string"}
}
matches with additional properties only if they are strings.
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"address": { "type": "string" },
"telephone": { "type": "string" }
},
"required": ["name", "email"]
}
Built-in formats:
"date-time": Date representation, as defined by RFC 3339, section 5.6.
"email": Internet email address, see RFC 5322, section 3.4.1.
"hostname": Internet host name, see RFC 1034, section 3.1.
"ipv4": IPv4 address, according to dotted-quad ABNF syntax as defined in RFC 2673, section 3.2.
"ipv6": IPv6 address, as defined in RFC 2373, section 2.2.
"uri": A universal resource identifier (URI), according to RFC3986.
"uri-reference": New in draft 6 A URI Reference (either a URI or a relative-reference), according to RFC3986, section 4.1.
Numeric Types
{ "type": "integer" }
{ "type": "number", "multipleOf": 1.0 }
{ "type": "number" }
{
"type" : "number",
"multipleOf" : 10
}
{
"type": "number",
"minimum": 0,
"exclusiveMaximum": 100
}
Object Type
{ "type": "object" }
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": {
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
}
}
Restrictions on property names and number of properties:
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}
Property Dependencies:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"required": ["name"],
"dependencies": {
"credit_card": ["billing_address"]
}
}
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"required": ["name"],
"dependencies": {
"credit_card": ["billing_address"],
"billing_address": ["credit_card"]
}
}
Schema dependencies:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }
},
"required": ["name"],
"dependencies": {
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
},
"required": ["billing_address"]
}
}
}
matches
{
"name": "John Doe",
"credit_card": 5555555555555555,
"billing_address": "555 Debtor's Lane"
}
and
{
"name": "John Doe",
"billing_address": "555 Debtor's Lane"
}
but not
{
"name": "John Doe",
"credit_card": 5555555555555555
}
Pattern Properties:
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": false
}
matches
{ "S_25": "This is a string" }
{ "I_0": 42 }
but not
{ "S_0": 42 }
{
"type": "object",
"properties": {
"builtin": { "type": "number" }
},
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": { "type": "string" }
}
matches
{ "builtin": 42 }
{ "keyword": "value" }
but not
{ "keyword": 42 }
Arrays:
{ "type": "array" }
matches
[1, 2, 3, 4, 5]
[3, "different", { "types" : "of values" }]
but not
{"Not": "an array"}
Array Items:
{
"type": "array",
"items": {
"type": "number"
}
}
[1, 2, 3, 4, 5] ok
[1, 2, "3", 4, 5] not ok
{
"type": "array",
"contains": {
"type": "number"
}
}
["life", "universe", "everything", 42] ok
["life", "universe", "everything", "forty-two"] not ok
Tuple validation:
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
]
}
matches
[1600, "Pennsylvania", "Avenue", "NW"]
[10, "Downing", "Street"]
[1600, "Pennsylvania", "Avenue", "NW", "Washington"]
can add
"additionalItems": false
at the end to disallow "Washington"
or
"additionalItems": { "type": "string" }
to allow additional string items in the array
array lengths:
{
"type": "array",
"minItems": 2,
"maxItems": 3
}
{
"type": "array",
"uniqueItems": true
}
no duplicates allowed
Boolean type:
{ "type": "boolean" }
true
false
Metadata:
title: title of schema
description: description of schema
default: default value for missing required items
examples: examples of json that should validate
{
"title" : "Match anything",
"description" : "This is a schema that matches anything.",
"default" : "Default value",
"examples" : [ "Anything", 4035 ]
}
enumerated type:
{
"type": "string",
"enum": ["red", "amber", "green"]
}
{
"enum": ["red", "amber", "green", null, 42]
}
Combining Schemas:
anyOf, allOf, oneOf, not
{
"anyOf": [
{ "type": "string", "maxLength": 5 },
{ "type": "number", "minimum": 0 }
]
}
"short" ok
12 ok
"too long" not ok
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
{
"allOf": [
{ "type": "string" },
{ "type": "number" }
]
}
same as
false
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
exactly one
10 ok
9 ok
2 not ok
15 not ok
{ "not": { "type": "string" } }
Pattern:
• A single unicode character (other than the special characters below) matches itself.
• ^: Matches only at the beginning of the string.
• $: Matches only at the end of the string.
• (...): Group a series of regular expressions into a single regular expression.
• |: Matches either the regular expression preceding or following the | symbol.
• [abc]: Matches any of the characters inside the square brackets.
• [a-z]: Matches the range of characters.
• [^abc]: Matches any character not listed.
• [^a-z]: Matches any character outside of the range.
• +: Matches one or more repetitions of the preceding regular expression.
• *: Matches zero or more repetitions of the preceding regular expression.
• ?: Matches zero or one repetitions of the preceding regular expression.
• +?, *?, ??: The *, +, and ? qualifiers are all greedy; they match as much text as possible. Sometimes this behavior
isn’t desired and you want to match as few characters as possible.
• (?!x}, (?=x}: Negative and positive lookahead.
• {x}: Match exactly x occurrences of the preceding regular expression.
• {x,y}: Match at least x and at most y occurrences of the preceding regular expression.
• {x,}: Match x occurrences or more of the preceding regular expression.
• {x}?, {x,y}?, {x,}?: Lazy versions of the above expressions.
{
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
Reuse (definitions)
{
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
You can place the above in the "definitions" section:
{
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
}
}
and refer to it as:
{ "$ref": "#/definitions/address" }
or if definitions is in a separate file:
{ "$ref": "definitions.json#/address" }
More interesting example:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
}
}
matches
{
"shipping_address": {
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC"
},
"billing_address": {
"street_address": "1st Street SE",
"city": "Washington",
"state": "DC"
}
}
Recursion:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#/definitions/person" },
"default": []
}
}
}
},
"type": "object",
properties": {
"person": { "$ref": "#/definitions/person" }
}
}
matches:
{
"person": {
"name": "Elizabeth",
"children": [
{
"name": "Charles",
"children": [
{
"name": "William",
"children": [
{ "name": "George" },
{ "name": "Charlotte" }
]
},
{
"name": "Harry"
}
]
}
]
}
}
Following would cause a problem (loop??)
{
"definitions": {
"alice": {
"anyOf": [
{ "$ref": "#/definitions/bob" }
]
},
"bob": {
"anyOf": [
{ "$ref": "#/definitions/alice" }
]
}
}
}