Overview
JavaScript Object Notation (JSON) is an open-standard file format that uses human-readable text to transmit data objects consisting of attribute–value pairs and array data types. JSON is based on JavaScript and is easy to read & write. Since every browser supports JavaScript, JSON has become the de-facto form for data interchange. A tool like JSON schema is required to validate the data against the schema.
Understanding JSON Schema
A record’s design mainly depends on its intended usage in the application. It is important to know the organization of a record, the fields that represent the record and the expected values of each of those fields.
JSON schema plays a critical role in helping both the developer & consumer in understanding the representation of JSON document.
Generally, JSON is built using various data structures:
Object:{
"userName": "BillGates",
"emailId":"bill.gates@microsoft.com"
}
- Array:
[ "Male", "Female" ]
- Number:
35 10.5678
- String:
"Welcome!! This is a text page"
- Boolean:
true,false
- Null:
null
Using these simple data types, every kind of JSON document can be represented. To validate the values provided in the JSON document, we can define a JSON schema with the below building blocks:
- The elements & attributes that the document can contain
- Data types of elements
- Formats for values of the elements
- Restrictions on the length of the values
- Enumeration for an element with a fixed set of values
Declaring JSON Schema
JSON schema is written as a JSON. Hence, the keyword schema is used to differentiate the schema from a regular JSON.
{
"$schema": "http://json-schema.org/schema#"
}
To define the data type of the schema, the keyword ‘type’ is used, and it can be either a string or an array. If the data type is string, it has to be one of the basic types. If it is an array, each element in the array is unique and it has to be one of the basic types. If the type is an array, JSON is valid if it matches any of the array elements.
As shown below, JSON schema supports various data types:
-
String
- It is used for text and contains Unicode characters.
The string can be validated for its length using maxlength & minlength keywords.{ "type": "string" }
And, the pattern of the string can be restricted using a regular expression.{ "type": "string", "minLength": "3", "maxLength": "5" }
{ "type": "string", "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$" }
Formatted keyword can be used for basic validation of semantics on strings. Some of the built-in formats are date, time, URI, etc.{ "type": "string", "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$" }
{ "type": "string", "format": "date" }
- It is used for text and contains Unicode characters.
-
Numeric Types
- JSON schema supports two numeric types i.e., integer and number
- Integer is used for integral numbers
{ "type": "integer" }
- Ex: 42
- Ex: -1
- Number is used for numeric types
{ "type": "number" }
- Ex: 42
- Ex: 5.0
- -1
- Range of numbers is specified using minimum, maximum, exclusiveMinimum and exclusiveMaximum
{ "type": "number", "minimum": 0, "exclusiveMaximum": 100 }
-
Object
- The Object is a mapping type that maps keys to values, where a key has to be a string
- The key-value pair is called a property
{ "type": "object" }
- Ex
{ "key1": "value1", "key2": "value2" }
- The properties on an object are defined using the keywords and properties
{ "type": "object", "properties": { "streetAddress1": {"type": "string"}, "streetAddress2": {"type": "string"} } }
- By default, the properties are optional. The list of mandatory properties can be provided using the keyword, required.
{ "type": "object", "properties": { "streetAddress1": {"type": "string"}, "streetAddress2": {"type": "string"}, "required": ["streetAddress1"] } }
- We can declare the dependencies between properties using the keyword, dependencies
- For example, we can define the schema of a customer in a way that the billing address is required only if the credit card number is provided
{ "type": "object", "properties": { "name": {"type": "string"}, "creditCardNumber": {"type": "number"}, "billingAddress": {"type": "string"} }, "required": ["name"], "dependencies": { "creditCardNumber": [billingAddress] } }
- To restrict the caller from providing additional properties with the data that are not defined in the schema, the keyword additionalProperties can be used
{ "type": "object", "properties": { "name": {"type": "string"}, "creditCardNumber": {"type": "number"} }, "required": ["name"], "additionalProperties": false }
-
Array
- Arrays can be used for ordered items and in JSON wherein each element can be of a different data type
{"type": "array"}
- Example
[1,2,3,4,5]
- Arrays can be used for ordered items and in JSON wherein each element can be of a different data type
-
Boolean
- boolean type matches only two values, true & false
{"type": "boolean"}
- boolean type matches only two values, true & false
-
Null
- To represent a missing value, the null type can be used that has only one value, null
{"type": "null"}
- To represent a missing value, the null type can be used that has only one value, null
-
Enumerated Values
- To restrict a value to a fixed set of values, enum keyword can be used and it must be an array with at least one element
- Each element of the enum is unique
{ "type": "string", "enum": ["male", "female"] }
Example
Let us consider a JSON document that represents the customer data such as name, age, gender, email address, billing & shipping addresses and credit card number.
{
"name": "Kris Fletcher ",
"gender": "male",
"age": 30,
"joiningDate": "2017-11-13",
"emailId": "kris@gmail.com",
"contactNumber": "(410)804-4694",
"creditCardNumber": 9876543210987654,
"billingAddress": {
"streetAddress1": "394",
"type": "office"
}
}
The example depicts that fields such as name, street address 1, street address 2, city, etc. can accept any string, whereas, fields such as age, & credit card number only accept digits. And though the fields like email Id, contact number and joining date accept strings, the value should adhere to a specific format.
To validate the various specifications listed, we define a JSON schema as given below.
{
"$schema": "http://json-schema.org/draft-07/schema",
"definitions": {
"address": {
"type": "object",
"properties": {"streetAddress1": {"type": "string"}},
"required": ["streetAddress1"]
}
}
},
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 4, "maxLength": 64},
"gender": {"type": "string", "enum": ["male","female"]},
"age": {"type": "integer", "minimum": 18, "exclusiveMaximum": 100},
"joiningDate": {"type": "string","format": "date"},
"emailId": {
"type": "string",
"pattern": "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"
},
"contactNumber": {
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
},
"creditCardNumber": {"type": "integer"},
"billingAddress": {
"allOf": [
{"$ref": "#/definitions/address"},
{
"properties": {"type": {"enum": ["residential", "office"]}},
"required": ["type"]
}
]
},
"dependencies": {
"creditCardNumber": ["billingAddress"]
},
"additionalProperties": false,
"required": ["name", "emailId"]
}
Validating JSON Against Schema
JSON can be validated against the schema using json-schema of everit project. We need to add the corresponding maven dependency to the project’s pom.xml.
<dependency>
<groupId>org.everit.json</groupId>
<artifactId>org.everit.json.schema</artifactId>
<version>1.11.1</version>
</dependency>
Write a method as shown below to read both the JSON schema as well as JSON document and validate the document against the schema using the validate method of Schema class of everit API.
public void validateJsonDocument(String definition, String payload){
JSONObject jsonSchema = new JSONObject(definition);
JSONObject jsonData = new JSONObject(payload);
Schema schema = SchemaLoader.load(jsonSchema);
schema.validate(jsonData);
}
The validate method of Schema class returns either true or false after validating JSON.
Conclusion
This blog helps us in understanding the purpose & definition of JSON schema and various data types supported by JSON schema. Also, it helps us to validate the JSON document against the defined JSON schema by utilizing json-schema API of everit.
References
- https://json-schema.org/understanding-json-schema/
- https://www.baeldung.com/introduction-to-json-schema-in-java
- https://github.com/everit-org/json-schema
About Innominds
Innominds is a leading Digital Transformation and Product Engineering company headquartered in San Jose, CA. It offers co-creation services to enterprises for building solutions utilizing digital technologies focused on Devices, Apps, and Analytics. Innominds builds better outcomes securely for its clients through reliable advanced technologies like IoT, Blockchain, Big Data, Artificial Intelligence, DevOps and Enterprise Mobility among others. From idea to commercialization, we strive to build convergent solutions that help our clients grow their business and realize their market vision.
Interested! For any demos or POCs, please write to us at marketing@innominds.com and know more about our offerings.