- Introduction
- Starting the schema
- Defining the properties
- Going deeper with properties
- Nesting data structures
- References outside the schema
- Taking a look at data for our defined JSON Schema
Introduction #
The following example is by no means definitive of all the value JSON Schema can provide. For this you will need to go deep into the specification itself – learn more at https://json-schema.org/specification.html.
Let’s pretend we’re interacting with a JSON based product catalog. This catalog has a product which has:
- An identifier:
productId
- A product name:
productName
- A selling cost for the consumer:
price
- An optional set of tags:
tags
.
For example:
{
"productId": 1,
"productName": "A green door",
"price": 12.50,
"tags": [ "home", "green" ]
}
While generally straightforward, the example leaves some open questions. Here are just a few of them:
- What is
productId
? - Is
productName
required? - Can the
price
be zero (0)? - Are all of the
tags
string values?
When you’re talking about a data format, you want to have metadata about what keys mean, including the valid inputs for those keys. JSON Schema is a proposed IETF standard how to answer those questions for data.
Starting the schema #
To start a schema definition, let’s begin with a basic JSON schema.
We start with four properties called keywords which are expressed as JSON keys.
Yes. the standard uses a JSON data document to describe data documents, most often that are also JSON data documents but could be in any number of other content types like
text/xml
.
- The
$schema
keyword states that this schema is written according to a specific draft of the standard and used for a variety of reasons, primarily version control. - The
$id
keyword defines a URI for the schema, and the base URI that other URI references within the schema are resolved against. - The
title
anddescription
annotation keywords are descriptive only. They do not add constraints to the data being validated. The intent of the schema is stated with these two keywords. - The
type
validation keyword defines the first constraint on our JSON data and in this case it has to be a JSON Object.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product in the catalog",
"type": "object"
}
We introduce the following pieces of terminology when we start the schema:
- Schema Keyword:
$schema
and$id
. - Schema Annotations:
title
anddescription
. - Validation Keyword:
type
.
Defining the properties #
productId
is a numeric value that uniquely identifies a product. Since this is the canonical identifier for a product, it doesn’t make sense to have a product without one, so it is required.
In JSON Schema terms, we update our schema to add:
- The
properties
validation keyword. - The
productId
key.description
schema annotation andtype
validation keyword is noted – we covered both of these in the previous section.
- The
required
validation keyword listingproductId
.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
}
},
"required": [ "productId" ]
}
productName
is a string value that describes a product. Since there isn’t much to a product without a name it also is required.- Since the
required
validation keyword is an array of strings we can note multiple keys as required; We now includeproductName
. - There isn’t really any difference between
productId
andproductName
– we include both for completeness since computers typically pay attention to identifiers and humans typically pay attention to names.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
}
},
"required": [ "productId", "productName" ]
}
Going deeper with properties #
According to the store owner there are no free products. 😉
- The
price
key is added with the usualdescription
schema annotation andtype
validation keywords covered previously. It is also included in the array of keys defined by therequired
validation keyword. - We specify the value of
price
must be something other than zero using theexclusiveMinimum
validation keyword.- If we wanted to include zero as a valid price we would have specified the
minimum
validation keyword.
- If we wanted to include zero as a valid price we would have specified the
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
}
},
"required": [ "productId", "productName", "price" ]
}
Next, we come to the tags
key.
The store owner has said this:
- If there are tags there must be at least one tag,
- All tags must be unique; no duplication within a single product.
- All tags must be text.
- Tags are nice but they aren’t required to be present.
Therefore:
- The
tags
key is added with the usual annotations and keywords. - This time the
type
validation keyword isarray
. - We introduce the
items
validation keyword so we can define what appears in the array. In this case:string
values via thetype
validation keyword. - The
minItems
validation keyword is used to make sure there is at least one item in the array. - The
uniqueItems
validation keyword notes all of the items in the array must be unique relative to one another. - We did not add this key to the
required
validation keyword array because it is optional.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
},
"tags": {
"description": "Tags for the product",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": [ "productId", "productName", "price" ]
}
Nesting data structures #
Up until this point we’ve been dealing with a very flat schema – only one level. This section demonstrates nested data structures.
- The
dimensions
key is added using the concepts we’ve previously discovered. Since thetype
validation keyword isobject
we can use theproperties
validation keyword to define a nested data structure.- We omitted the
description
annotation keyword for brevity in the example. While it’s usually preferable to annotate thoroughly in this case the structure and key names are fairly familiar to most developers.
- We omitted the
- You will note the scope of the
required
validation keyword is applicable to the dimensions key and not beyond.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
},
"tags": {
"description": "Tags for the product",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"dimensions": {
"type": "object",
"properties": {
"length": {
"type": "number"
},
"width": {
"type": "number"
},
"height": {
"type": "number"
}
},
"required": [ "length", "width", "height" ]
}
},
"required": [ "productId", "productName", "price" ]
}
References outside the schema #
So far our JSON schema has been wholly self contained. It is very common to share JSON schema across many data structures for reuse, readability and maintainability among other reasons.
For this example we introduce a new JSON Schema resource and for both properties therein:
- We use the
minimum
validation keyword noted earlier. - We add the
maximum
validation keyword. - Combined, these give us a range to use in validation.
{
"$id": "https://example.com/geographical-location.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Longitude and Latitude",
"description": "A geographical coordinate on a planet (most commonly Earth).",
"required": [ "latitude", "longitude" ],
"type": "object",
"properties": {
"latitude": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"longitude": {
"type": "number",
"minimum": -180,
"maximum": 180
}
}
}
Next we add a reference to this new schema so it can be incorporated.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
},
"tags": {
"description": "Tags for the product",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"dimensions": {
"type": "object",
"properties": {
"length": {
"type": "number"
},
"width": {
"type": "number"
},
"height": {
"type": "number"
}
},
"required": [ "length", "width", "height" ]
},
"warehouseLocation": {
"description": "Coordinates of the warehouse where the product is located.",
"$ref": "https://example.com/geographical-location.schema.json"
}
},
"required": [ "productId", "productName", "price" ]
}
Taking a look at data for our defined JSON Schema #
We’ve certainly expanded on the concept of a product since our earliest sample data (scroll up to the top). Let’s take a look at data which matches the JSON Schema we have defined.
{
"productId": 1,
"productName": "An ice sculpture",
"price": 12.50,
"tags": [ "cold", "ice" ],
"dimensions": {
"length": 7.0,
"width": 12.0,
"height": 9.5
},
"warehouseLocation": {
"latitude": -78.75,
"longitude": 20.4
}
}
To follow along with this tutorial, you’ll need a MongoDB Atlas account and to download MongoDB Compass.
JSON (JavaScript Object Notation) is a simple and lightweight text-based data format. JSON Schema is an IETF standard providing a format for what JSON data is required for a given application and how to interact with it. Applying such standards for a JSON document lets you enforce consistency and data validity across similar JSON data.
.Let’s take a look at a document example with a person’s name and their indoor and outdoor hobbies.
{
"id": 7,
"name": "John Doe",
"age": 22,
"hobbies": {
"indoor": [
"Chess"
],
"outdoor": [
"BasketballStand-up Comedy"
]
}
}
If you were to look at the above example, you would not necessarily know if id
can be zero (0). You would also not know if you could leave age
blank. For this reason, we need to have metadata that holds information about valid data types and the description of the keys. Additionally, JSON Schema gives you a standard way to structure the metadata.
Basic JSON Schema Example
Let’s look at an example of a JSON Schema for the above document type.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/employee.schema.json",
"title": "Record of employee",
"description": "This document records the details of an employee",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for an employee",
"type": "number"
},
"name": {
"description": "Full name of the employee",
"type": "string"
},
"age": {
"description": "Age of the employee",
"type": "number"
},
"hobbies": {
"description": "Hobbies of the employee",
"type": "object",
"properties": {
"indoor": {
"type": "array",
"items": {
"description": "List of indoor hobbies",
"type": "string"
}
},
"outdoor": {
"type": "array",
"items": {
"description": "List of outdoor hobbies",
"type": "string"
}
}
}
}
}
}
It could look daunting at first glance but we will break it down to understand further.
JSON Schema Keywords and Properties
We have different keywords that are used in the above example. The following list explains what each of these keywords mean.
- $schema: States that this schema complies with v4 of the IETF standard
- $id: Defines the base URI to resolve other URI references within the schema.
- title: Describes the intent of the schema.
- description: Gives the description of the schema.
- type: Defines the type of data.
- properties: Defines various keys and their value types within a JSON document.
- minimum: Defines the minimum acceptable value for a numeric datatype.
- items: Enumerates the definition for the items that can appear in an array.
- minItems: Defines the minimum number of items that should appear in an array.
- uniqueItems: Enforces if every item in the array should be unique relative to one another.
- required: Lists the keys that are required and mandatory.
For a full list of keywords, visit json-schema.org. The link explains the keywords that you can use in your schema and their purpose.
How do I create a JSON schema?
You can use online JSON schema generators if you have a simple JSON document, then modify the schema as per the requirement of your project. Alternatively, you can build a JSON schema of your own from scratch by following the steps below
Starting the Schema
If you have already familiarized yourself with the JSON schema keywords and properties, we can jump right into starting a basic JSON schema. Lets begin with five basic keywords to define an employee.
Base Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Record of Employee",
"description": "This document records the details of an employee",
"type": "object"
}
In the above example, $schema
links to the resource that identifies the dialect and the valid schemas written for this dialect.
$id
keyword identifies the schema resource. Here are a couple of things to know about this keyword:
- The URI in this keyword is an identifier and not necessarily a network locator.
- It must be a string.
- It must represent a valid URI reference that is normalized and resolves absolute URI.
- It must not contain a non empty fragment.
- It should not contain an empty fragment.
title
keyword gives a short description of the schema and you can use the description
keyword to explain more about the schema. In the above example, the title hints that this schema is about a record of an employee and the description explains that in detail.
type
keyword explains the valid data type of a record. In the above example, type sets the constraint for this document and tells us that this record is an object.
JSON Schema Properties
The Entry Schema
The schema that we have used in the above section is a basic outline. Lets build on it by adding an id
field to the employee record.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/employee.schema.json",
"title": "Record of employee",
"description": "This document records the details of an employee",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for an employee",
"type": "number"
}
}
}
We have added two sub-properties, “id.description”, stating that it is a unique identifier, and “id.type”, explaining that it is a number.
Let’s do the same for name and age — but this time, with new keywords.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/employee.schema.json",
"title": "Record of employee",
"description": "This document records the details of an employee",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for an employee",
"type": "string"
},
"name": {
"description": "full name of the employee",
"type": "string"
"minLength":2
},
"age": {
"description": "age of the employee",
"type": "number",
"minimum": 16
}
},
"required": [
"id"
"name",
"age"
]
}
In the name property, we have introduced the minLength
keyword to make sure that the property has at least two characters. Similarly, in the age property, we have used the minimum
keyword to ensure that the age of the employee exceeds 16 everytime. It can be of type number or type integer. We have also used the required
keyword to define the mandatory properties. Now, let’s take it a step further and add an object inside the employee object.
Nesting Data Structures
To add an object inside an object in JSON format, we use nested data structure. Creating subschemas for Nested objects work quite similarly to the creating schemas for root objects. You can use all the schema keywords that you used when defining the root object except for $schema
and $id
. They only have to be stated at the beginning of a schema.
Arrays of Things
The following example shows how we can create an object within an object that takes an array type data. Here, we will use a few new keywords in addition to the ones we have already used.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$id": "https://example.com/employee.schema.json",
"title": "Record of employee",
"description": "This document records the details of an employee",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for an employee",
"type": "number"
},
"name": {
"description": "name of the employee",
"type": "string",
"minLength":2
},
"age": {
"description": "age of the employee",
"type": "number",
"minimum": 16
},
"hobbies": {
"description": "hobbies of the employee",
"type": "object",
"properties": {
"indoor": {
"type": "array",
"items": {
"description": "List of hobbies",
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"outdoor": {
"type": "array",
"items": {
"description": "List of hobbies",
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": [
"indoor",
"outdoor"
]
}
},
"required": [
"id",
"name",
"age",
"hobbies"
],
"additionalProperties": false
}
In the above example, we have defined two array fields – indoor and outdoor in the “hobbies” object. You might have noticed the items
keyword. This keyword defines the properties of each item.
Similarly, minItems
defines the minimum number of items that must be present in the array, maxItems
defines the maximum number of items that can be present within the array uniqueItems
uniquely identifies each item.
You will also see the required keyword again within the subobject. Like the required keyword in the root JSON object, the required keyword within the subobject dictates the mandatory properties within the subobjects.
Lastly, we have also introduced additionalProperties
. In the above example, it is a boolean taking the value false , telling us that we can’t use any other property that isn’t listed under the properties
keyword.
However, additionalProperties
doesn’t necessarily have to be a boolean. It can also be an object. For example, in the schema below, this keyword is stating that any additional property that we use under this schema is required to be of type string.
"additionalProperties": { "type": "string" }
Describing Geographical Coordinates
Though the above example is limited to a use case, there are limitless uses of JSON schema. One of the areas where JSON schema can be used to validate and enforce consistency is with geographical coordinates. Because of the nature of the data, there is a high chance of accepting invalid or inconsistent data.
In the example below, we can see that coordinates are represented using numeric data types.
{
"latitude": 58.858093,
"longitude": 22.294694
}
But there is a limit to the value that we can use for a coordinate i.e., the values cannot be more than 90 or less than negative 90. So let’s create a JSON schema to address this scenario.
{
"$id": "https://example.com/geographical-location.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Longitude and Latitude Values",
"description": "A geographical coordinate.",
"required": [ "latitude", "longitude" ],
"type": "object",
"properties": {
"latitude": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"longitude": {
"type": "number",
"minimum": -180,
"maximum": 180
}
}
}
Here you can see that we have used the minimum
and maximum
keyword for each property to limit the range of acceptable values. This not only resolves the issue with data validation but also ensures that incorrect values do not get through.
Using Your Schema for Validation in MongoDB Atlas
You can use $jsonSchema in a document validator to enforce the specified schema on insert and update operations in MongoDB, including in MongoDB Atlas. Since MongoDB stores the data in BSON (Binary JSON), you can easily store and retrieve all your data in JSON format.
MongoDB also lets you enforce a schema to validate your data and maintain a data structure. We will use MongoDB Atlas and MongoDB Compass to demonstrate how.
Suppose we insert the following documents into a collection named employees inside a database named mongodatabase.
Document 1
{
"id": 7,
"name": "John Doe",
"age": 22,
"hobbies": {
"indoor": [
"Chess"
],
"outdoor": [
"Basketball"
]
}
}
Document 2
{
"id": 8,
"name": "Jonathon Smith",
"age": 22
}
Document 3
{
"id": 1,
"name": "Jane Doe",
"age": 25,
"hobbies": {
"indoor": [
"Chess"
],
"outdoor": [
"Football"
]
}
}
We will enforce the schema from the previous section to validate these documents in MongoDB Compass.
Firstly, let’s connect our cluster with our Compass.
- Log into MongoDB Atlas and click Clusters
- Click on CONNECT to connect with your cluster.
- Set up connection security by adding your IP address and creating a database user. Then select Choose a connection method.
- Select Connect using MongoDB Compass.
- Download MongoDB Compass if you have not already and copy the connection string.
- Open MongoDB Compass and paste the connection string. Your connection string should look similar to this:
mongodb+srv://<username>:<password>@cluster0.9ddm0.mongodb.net/test
Replace <username> and <password> with the username and password of the database user that you created.
Now, let’s go into the mongodatabase and look at the documents inside the employees collection.
Click on the Validation tab and insert the following JSON schema to validate our documents. Begin the schema definition with $jsonSchema
keyword. Because we don’t need the $id and $schema keywords to get started, we will remove them.
{
$jsonSchema: {
"title": "Record of employee",
"description": "This document records the details of an employee",
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for an employee",
"type": "number"
},
"name": {
"description": "name of the employee",
"type": "string",
"minLength":2
},
"age": {
"description": "age of the employee",
"type": "number",
"minimum": 16
},
"hobbies": {
"description": "hobbies of the employee",
"type": "object",
"properties": {
"indoor": {
"type": "array",
"items": {
"description": "List of hobbies",
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"outdoor": {
"type": "array",
"items": {
"description": "List of hobbies",
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": [
"indoor",
"outdoor"
]
}
},
"required": [
"id",
"name",
"age",
"hobbies"
],
"additionalProperties": false
}
}
If you have followed the steps so far, you should get the following result.
As our schema requires a hobbies field in every document, the document with the id: 8 fails because it didn’t contain the required field.
You can also set additional validation rules by following the documentation on setting validation rules for your schema. To match documents that satisfy the specified JSON Schema, you can use the $jsonSchema
operator. The MongoDB JSON Schema documentation is an excellent resource to get you up and running.
To learn more about MongoDB Atlas, refer to this article.
Next Steps
By now, you should understand the JSON Schema, why it is used, and how we can use it. We have certainly expanded on the concept and how you can use it with MongoDB but there is more to cover.
If you want to learn more about JSON Schema with MongoDB, we recommend you go through MongoDB’s JSON Schema validation resource. If you are interested in knowing more about JSON Schema validation generally, visit this article.
FAQs
What is JSON Schema?
What is the use of JSON Schema?
How do I create a JSON Schema?
Is JSON Schema an industry standard for defining JSON structure?
Where should I submit the $jsonSchema data?
Рассмотрим следующий JSON-документ.
{
"artists" : [
{
"artistname" : "Deep Purple",
"formed" : "1968"
},
{
"artistname" : "Joe Satriani",
"born" : "1956-07-15"
},
{
"artistname" : "Maroon 5",
"formed" : "1994"
}
]
}
В данном примере применяется разный формат даты у объектов. Кроме того, один объект использует born (указывает, когда родился исполнитель), в то время как другие используют formed (когда образовалась группа/исполнитель).
В JSON нет правил, согласно которым некоторые объекты должны использовать определённый тип данных или даже содержать одинаковые поля. Им даже не нужно содержать одинаковое количество полей. Например, мы можем добавить поле favoritecolor к одному объекту, не добавляя его к другим.
Кроме того, нет правила, согласно которому данные должны быть в заданном формате. Например, поле born может быть представлено любым из следующих способов.
"born" : "1956"
"born" : 1956
"born" : "Июль 15, 1956"
"born" : "1956-07-15"
"born" : "07/15/1956"
"born" : "15/07/1956"
"born" : "Я люблю апельсины!"
"born" : [
{
"albumname" : "Flying in a Blue Dream",
"year" : "1989",
"genre" : "Инструментальный рок"
},
{
"albumname" : "The Extremist",
"year" : "1992",
"genre" : "Инструментальный рок"
},
{
"albumname" : "Shockwave Supernova",
"year" : "2015",
"genre" : "Инструментальный рок"
}
]
"born" : "Упс!!!"
Да, верно — «Упс!!!». Вы можете вставить туда что угодно.
Эта гибкость — одна из вещей, которая делает JSON таким простым в использовании. Но она же одновременно может вызвать проблемы, показанные выше. Многие приложения, которые читают JSON-файлы, требуют, чтобы данные были в стандартном формате. Но даже если приложения это прочитают, людям будет трудно понять, какой именно датой является «Я люблю апельсины!».
Поэтому при работе с JSON часто требуется задать ограничения для типов данных, которые могут попадать в файл. Например, чтобы все даты вводились в определённом формате, скажем, ГГГГ-ММ-ДД. Или убедиться, что пользователи вводят только число в поле возраста.
Создание схемы
Вы можете применять правила для своих JSON-файлов, создав схему, которая позволяет указать, какой тип данных может добавляться в ваши файлы. Также схема может использоваться для проверки JSON-файла, чтобы убедиться, что он содержит только правильный тип данных.
Например, вы можете использовать следующий код, чтобы ограничиться только строкой.
{ "type": "string" }
Вот пример базовой схемы JSON Schema (взят с json-schema.org).
{
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}
Можете использовать эту схему для проверки правильности ввода пользователем имени и возраста.
Как видите, JSON Schema на деле является тем же JSON. Так что не всегда легко определить что перед вами: JSON Schema или обычный JSON-документ.
Тем не менее, хорошей практикой считается размещение описания в верхней части схемы. Тогда описание объявляет, что перед нами схема JSON и оно поможет распознать, JSON Schema это или просто обычный JSON-документ.
Чтобы объявить JSON Schema, используйте ключевое слово $schema.
{ "$schema": "http://json-schema.org/schema#" }
В данном примере объявляется JSON Schema, написанная для текущей версии спецификации.
Вы также можете указать явно, какую версию спецификации используете. В следующем примере объявляется JSON Schema, написанная для JSON Schema, черновая версия 4.
{ "$schema": "http://json-schema.org/draft-04/schema#" }
Для создания JSON Schema ознакомьтесь с JSONSchema.net. Это онлайн-инструмент, который автоматически генерирует JSON Schema из любого введённого вами JSON.
Последнее изменение: 11.10.2019
JSON Schema is a declarative way of writing validation rules. It contains
all the steps that are necessary to be performed in order to validate something.
The format used to write these steps is, of course,
JSON itself.
Opis JSON Schema is the software/library (for PHP) that performs those steps
and tells you the validation status.
Data types
Because JSON Schema is written in JSON format, it supports all JSON
types plus an addition: the integer type, which is a subtype of the number type.
string
– represents a string/text, e.g."a string"
,"other string"
number
– represents an integer or a float, e.g.-5
,10
,
-5.8
,10.2
integer
– represents an integer, e.g.-100
,125
,
0
boolean
– represents a boolean value, e.g.true
orfalse
null
– indicates that a value is missing, e.g.null
object
– a key-value map, where the key must be astring
and the
value can be any type, e.g.{"key": "value", "other-key": 5}
array
– an ordered list of any data types, e.g.[1, -2.5, "some string", null]
Document structure
A valid json schema document must be a JSON object or a boolean value.
If it is a boolean, then the validation status is indicated by the value
of the boolean: true
– valid, false
– invalid.
If it is an object, then it must contain the steps needed for validation.
These steps come in the form of keywords and every keyword has a specific meaning.
Keywords are applied to data starting from the root of the document schema
and descend to their children.
Here are some examples
true
false
{}
Schema
Examples
Input | Status |
---|---|
"test" |
valid |
123 |
invalid |
Some keywords are purely decorative, like metadata keywords, which just describe the author intent.
Others are for identifying a document or a subschema, and the rest of them are for
validity checks. Usually keywords work independently and there are only a few
exceptions.
$schema keyword
This keyword is used to specify the desired schema version.
The value of this keyword must be a string representing an URI.
Currently the supported URIs are:
https://json-schema.org/draft/2020-12/schema
– latest versionhttps://json-schema.org/draft/2019-09/schema
– previous versionhttp://json-schema.org/draft-07/schema#
http://json-schema.org/draft-06/schema#
This keyword is not required and if it is missing, the URI of the
latest schema version will be used instead.
Not all keywords all available on all drafts, so we recommend using this keyword to set the right context.
$id keyword
This keyword is used to specify an unique ID for a document or a document subschemas.
The value of this keyword must be a string representing an URI. All subschema
IDs are resolved relative to the document’s ID.
It is not a required keyword, but we recommend you using it, as a best practice.
The usage of this keyword will be covered in the next chapters.
$anchor keyword
This keyword is used to define fragment identifiers.
The two schemas below are equivalent.
$anchor
{
"$id": "http://example.com",
"$ref": "#mail",
"$defs": {
"mail": {
"$anchor": "mail",
"format": "email"
}
}
}
$id
{
"$id": "http://example.com",
"$ref": "#mail",
"$defs": {
"mail": {
"$id": "#mail",
"format": "email"
}
}
}
definitions keyword
This keyword does not directly validate data, but it contains a map
of validation schemas. The value of this keyword can be anything.
This keyword is not required.
$defs keyword
Same as definitions
keyword (standardized staring with draft-2019-09).
These keywords are not used for validation, but to describe the
validation schema and how it works. All keywords are optional.
title
Contains a short description about the validation. The value of this
keyword must be a string.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/number.json#",
"title": "Test if it is a number",
"type": "number"
}
description
Contains a long description about the validation. The value of this
keyword must be a string.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/number.json#",
"title": "Test if it is a number",
"description": "A data is considered number if it is an integer or a float.",
"type": "number"
}
examples
Contains a list of valid examples. The value of this keyword must be
an array.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/number.json#",
"title": "Test if it is a number",
"description": "A data is considered a number if is an integer or a float.",
"examples": [-5.10, -2, 0, 5, 8.10],
"type": "number"
}
Contains an observation about the schema. The value of this keyword must be a string.
{
"$comment": "We should replace this broken regex with format: email.",
"type": "string",
"pattern": "[a-zA-Z0-9\.]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,3}"
}
JSON Schema examples
For most of the basic examples we will not use $schema
, $id
and metadata keywords.
Don’t worry if you don’t exactly understand every keyword, they are presented
in depth in the next chapters.
Validating a simple user
Schema
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"age": {
"type": "integer",
"minimum": 18,
"maximum": 150
}
},
"required": ["email"]
}
Examples
Input | Status |
---|---|
{"name": "John", "email": "john@example.com", "age": 25} |
valid |
{"email": "john@example.com"} |
valid – only the email is required |
{"name": "John", "age": 25} |
invalid – required email is missing |
{"name": "John", "email": "john(at)example.com", "age": 25} |
invalid – not a valid email address |
{"email": 123} |
invalid – email must be a string |
{"email": "john@example.com", "age": 25.5} |
invalid – age must be an integer |
"john@example.com" |
invalid – must be an object |
Validating a list
Schema
{
"type": "array",
"minItems": 2,
"items": {
"type": ["string", "number"]
}
}
Examples
[1, "a"] |
valid |
[-5.1, 10.8, 2] |
valid |
["a", "b", "c", "d", 4, 5] |
valid |
[1] |
invalid – must have at least 2 items |
["a", {"x": 1}] |
invalid – contains an object |
{"0": 1, "1": 2} |
invalid – not an array |
Copyright © Zindex Software. All rights reserved
Example data
Let’s pretend we’re interacting with a JSON based product catalog. This catalog has a product which has an id, a name, a price, and an optional set of tags.
Example JSON data for a product API
An example product in this API is:
{ "id": 1, "name": "A green door", "price": 12.50, "tags": ["home", "green"] }
While generally straightforward, that example leaves some open questions. For example, one may ask:
- What is id?
- Is name required?
- Can price be 0?
- Are all tags strings?
When you’re talking about a data format, you want to have metadata about what fields mean, and what valid inputs for those fields are. JSON schema is a specification for standardizing how to answer those questions for JSON data.
Starting the schema
To start a schema definition, let’s begin with a basic JSON schema:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object" }
The above schema has four properties called keywords.
The title and description keywords are descriptive only, in that they do not add
constraints to the data being validated. The intent of the schema is stated with these two keywords
(that is, this schema describes a product).
The type keyword defines the first constraint on our JSON data: it has to be a JSON
Object.
Finally, the $schema keyword states that this schema is written according to the draft
v4 specification.
Defining the properties
Next let’s answer our previous questions about this API, starting with id.
What is id?
id is a numeric value that uniquely identifies a product. Since this is the canonical identifier for a product, it doesn’t make sense to have a product without one, so it is required.
In JSON Schema terms, we can update our schema to:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" } }, "required": ["id"] }
Is name required?
name is a string value that describes a product. Since there isn’t
much to a product without a name, it also is required. Adding this gives us the schema:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" } }, "required": ["id", "name"] }
Can price be 0?
According to Acme’s docs, there are no free products. In JSON schema a number can have a minimum. By default this minimum is inclusive, so we need to specify exclusiveMinimum. Therefore we can update our schema with price:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true } }, "required": ["id", "name", "price"] }
Are all tags strings?
Finally, we come to the tags property. Unlike the previous
properties, tags have many values, and is represented as a JSON array. According
to Acme’s docs, all tags must be strings, but you aren’t required to specify
tags. We simply leave tags out of the list of required properties.
However, Acme’s docs add two constraints:
- there must be at least one tag,
- all tags must be unique.
The first constraint can be added with minItems, and the second one by
specifying uniqueItems as being true:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "required": ["id", "name", "price"] }
Summary
The above example is by no means definitive of all the types of data JSON schema can define. For more definitive information see the full standard draft.
As a final example, here’s a spec for an array of products, with the products having 2 new properties. The first is a dimensions property for the size of the product, and the second is a warehouseLocation field for where the warehouse that stores them is geographically located.
And also, since JSON Schema defines a reference schema for a geographic location, instead of coming up with our own, we’ll reference the canonical one.
Set of products:
[ { "id": 2, "name": "An ice sculpture", "price": 12.50, "tags": ["cold", "ice"], "dimensions": { "length": 7.0, "width": 12.0, "height": 9.5 }, "warehouseLocation": { "latitude": -78.75, "longitude": 20.4 } }, { "id": 3, "name": "A blue mouse", "price": 25.50, "dimensions": { "length": 3.1, "width": 1.0, "height": 1.0 }, "warehouseLocation": { "latitude": 54.4, "longitude": -32.7 } } ]
Set of products schema:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product set", "type": "array", "items": { "title": "Product", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "number" }, "name": { "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "dimensions": { "type": "object", "properties": { "length": {"type": "number"}, "width": {"type": "number"}, "height": {"type": "number"} }, "required": ["length", "width", "height"] }, "warehouseLocation": { "description": "Coordinates of the warehouse with the product", "$ref": "http://json-schema.org/geo" } }, "required": ["id", "name", "price"] } }