JSON Schema. To be or not to be?

Architecture: the art of making unnecessarily necessary.

Frederick Kiesler

It’s no secret to anyone that for any web service using SOAP protocol in XML format, a reliable and time-tested solution is the preliminary development of the XML Schema (xsd-scheme), which describes the data types and structure of XML messages. With this approach, developers have a clear advantage: they have strict standardized rules for the structure of messages that are set in the scheme, the number of rules is finite, and they allow you to automate the verification of any new message in XML format.

But it is also known that the XML language has been supplanted by the JSON (JavaScript Object Notation) markup language due to its greater heaviness (XML heaviness), as well as the spread of the architectural style of REST (REpresentational State Transfer) software development for distributed systems. Although the REST style itself does not require the use of JSON (it can be said to require nothing at all, but “recommends”), but as practice shows, more often when developing a REST API, JSON is used to describe the body of messages.

So, the practice of developing a REST API with JSON messages has firmly entered the life of IT in Russia (and not only ours), although experience in describing the message structure in the form of XML Schema has greatly simplified the life of web service developers at one time, persistently ignored in the case of JSON messages. But not everyone that can not but rejoice.

When developers familiar with XML Schema faced the need to reinvent the wheel each time with document parsing and reinvent the validation logic, a similar JSON Schema draft was formed . It is available at json-schema.org, as well as a number of documents on the history of changes and examples of use. And despite the fact that it is published in draft status, it has long been supported by all popular development platforms and libraries in different languages. JSON Schema

itself provides fewer message structuring capabilities than XML Schema . What can be easily described through XML Schema will not always be a trivial task to repeat using JSON Schema, if at all possible. But here I would consider this fact as an advantage. Why? It is known that the simpler and more linear the algorithm of the system, the more reliable it is, the simpler the structure of the document, the easier it is for perception, etc. I can not help but quote:



"Everything ingenious is simple, and everything simple is ingenious . " And if it is not possible to describe the complex structure of the document and the set of acceptable options using the scheme, then perhaps it is worth looking in the direction of simplifying the structure and logic of the formation of this document?

Foreword


So what is this article about?

I would like to draw more attention to the benefits of describing JSON messages transmitted by the JSON Schema. Despite the fact that “at the entrance”, developing a REST API without any JSON scheme is always simpler and faster, but with the growth of the system, its absence in one way or another leads to a rise in the cost of maintaining and supporting the system. Also, any preliminary study of the message structure contributes to a better organization of the exchange of messages, without unnecessary duplication in the exchange of data and general rules for their processing.

Also, in order to disseminate information in the Russian-speaking community about the possibilities of JSON Schema and the rules for working with it, I will share my some experience with specific examples in the framework of this article.

Formulation of the problem


Before starting to study JSON and JSON Schema, I will describe the task on which we will consider all the examples below.

Consider a role management model in an organization. We assume that we will need to transfer reference information on the existing role model to dependent systems in messages in JSON format by calling a REST service.

Description of the task:

The organization has employees, they often have to work simultaneously in several systems. At the same time, the level of access (authority) to certain system components (resources) for different employees, depending on their role in the organization, may differ, and should be controlled during user authorization in the system.

For example, an accountant (role) will have read and edit access (operations / credentials) to payrolls (resource) for the salaries of all employees, and an analyst (role), for example, will have read access (operation / credentials) only according to its pay slip (resource).

It is necessary to design and describe a role management model in an organization. Available roles, a set of possible powers and resources in the system must be transferred to other systems upon request.


Figure 1. Presentation of the components of the role model. The

methods for describing and implementing the role model may differ, but regardless of the implementation, most often in the role model in this case, we can distinguish the following basic components:

  1. Role (e.g. manager, accountant, etc.).
  2. Resource (e.g., document, property, etc.).
  3. Operation / authority (e.g. read, print, create, etc.).

When describing role-based access (as one of the possible options), they resort to creating a discrete access matrix based on selected entities, for example:

Table 1. Discrete access matrix.
Resource: documentsResource: objects
Role: managerread, printread, create
Role: accountantread, createread

Further in the article, we will first familiarize ourselves with the theoretical component of the text format for exchanging JSON data and the rules for structuring them using JSON Schema, and as examples I will provide a description of reference entities for roles, resources and operations in the JSON language and their JSON schemes within our set task.

JavaScript Object Notation (JSON)


JSON (English JavaScript Object Notation) is a text-based data exchange format based on JavaScript.

Theory


The JSON markup language defines a limited set of data types. For the pair {“key”: value} for the “key” always use the type string, for the “value” the types are applicable: string, number, object (type JSON), array, boolean (true or false) and null.


Figure 2. JSON data types

The figure shows the basic types and examples of their use. Simple enough, in my opinion.

The JSON syntax is a subset of the JavaScript syntax, where:

  1. Data is written as pairs {“key”: value}.
  2. Data is separated by commas.
  3. Curly brackets record objects.
  4. Arrays are written in square brackets.
  5. The names of the "keys" are case-sensitive.


Figure 3. JSON Syntax

Practice


Consider an example of a role directory that we will transfer in the service:


Figure 4. Description of a role directory in json format

From the example, it can be seen that even despite such a small number of basic types, when combined, we can create more complex message structures if necessary. Here, in particular, I describe the directory of roles through an object of arrays containing other objects (in figure 4 are highlighted by two rectangles).

In tabular form using the json-visualization tools, the directory can be represented as follows:


Figure 5. Visualization of the directory of roles in JSON format

The directory, relatively speaking, represents 3 “tables” for assigning roles in a group of administrators, accountants, and workers. The composition of the “attributes” can be expanded, if necessary.

The visual representation, in my opinion, simplifies the perception of the text description. We will set a similar structure for the other two directories. I will give below an example of only a table view for a directory of authority (operations) and resources.


Figure 6. Visualization of the directory of permissions in JSON format


Figure 7. Visualization of the directory of resources in JSON

Source messages in the text JSON format for the directory of roles , resources and permissions can be downloaded / viewed from the link .
Now let's move on to the most interesting: to study JSON Schema and create a scheme for our reference books!

JSON Schema


Theory


Since the json schema is written in JSON format, it supports all JSON types plus the addition: the integer type, which is a subtype of the number type. The schema itself is a JSON object and is intended to describe data in JSON format. The following is a schema of the data types used to create the schema itself:


Figure 8. JSON Schema data types

As you can see from the figure, the schema uses all the same data types, as well as the same syntax principles as for a regular JSON document, shown on figure 3.

Now we will consider the most important - the rules used in the scheme for setting restrictions and structuring JSON messages.

JSON Schema allows you to:

  1. JSON.
  2. , — «keywords», .

Some "keywords" are purely descriptive, such as: "title", "description", etc., which simply describe the purpose of the scheme. Others are used to identify the document: "$ schema". This keyword is used to indicate the desired version of the schema. The value of this keyword should be a string representing a URI, for example: "$ schema": " json-schema.org/draft-04/schema# ".

It is very important to note here that not all versions can be supported by your circuit tool. But the 4th draft is supported by almost everyone. The latest changes (JSON Schema 2019-09 Release Notes) for different versions can be found at json-schema.org/draft/2019-09/release-notes.html .

The remaining keywords are used directly to validate the JSON document. We will now consider them.

Table 2. Analysis of the JSON Schema structure. Keywords and their examples of use.
A typeKeyword (s)Example / Description
"Keywords" to describe the scheme"$schema"
"$schema": http://json-schema.org/draft-04/schema#

Used to set the draft version of the scheme.
"$id"
"$id": "http://archi-blair.com/schemas/RolesDictionaryDef.json#"

Used to indicate a unique identifier for a document or its subcircuits.
"title"
"description"
"examples"
"comment"

{
"title": "JSON schema for dictionary",
"description": " ",
"examples": ["user", "manager"],
"comment": "     ))"
}

General "Validation keywords" independent of item data type"enum"
{"enum": [ "administrator", "superuser" ]}

A check is made to match at least 1 value.
"const"
{"const": "user" }

A check is made for exact compliance with the set value.
"type"
{"type": ["number", "string", "null", "boolean"]}
{"type": "array"}

Specifies the type of data that the schema will use. This keyword is optional, and the keyword value can be a string representing a valid data type, or an array of strings representing valid data types.
Keywords, ,"type": "string"

minLength
maxLength
pattern
contentEncoding
contentMediaType

{
"type": "string",
"minLength": 3,
"maxLength": 10,
"pattern": "^test\\/[a-z-]+$",
"contentEncoding": "base64",
"contentMediaType": "application/json"
}

.
"type": "number" "type": "integer"

minimum
exclusiveMinimum
maximum
exclusiveMaximum
multipleOf

{
  "type": "number",
  "minimum": 1.5,
   "exclusiveMinimum": true,
   "maximum": 12.3,
   "exclusiveMaximum": true,
   "multipleOf": 0.5
}

.
"type": "object"

properties
required
dependencies
minProperties
maxProperties
propertyNames
patternProperties
additionalProperties


"employees": {
 "description": "",
 "type": "array",
  "uniqueItems": true,
   "items": {
     "type": "object",
     "properties": {
           "name": {
               "type": "string",
               "enum": ["employee"],
               "enumNames": [""]
	    },
            "enabled": {
                "type": "boolean",
                "default": true
             }
    },
 "additionalProperties": false
 }
}

, ( ).
"type": "array"

minItems
maxItems
uniqueItems
contains
items
additionalItems


"employees": {
 "description": "",
 "type": "array",
 "uniqueItems": true,
 "items": {
    "type": "object",
    "properties": {
          "name": {
               "type": "string",
               "enum": ["employee"],
               "enumNames": [""]
            },
          "enabled": {
                "type": "boolean",
                "default": true
            }
     },
 "additionalProperties": false
 }
}

, ( ).
"type": "boolean"

{"type": "boolean"}

boolean (true false).
"type": "null"

{"type": "null"}

null «» .
"type": "____"
"format": "____"

{
  "type": "string",
  "format": "date"
}

format . , .. -, , , .
"type": "____"
"default": "____"

{
"enabled": {
	"type": "boolean",
	"default": true
}	

.

, .
"not"
"if-then-else"

{
  "not": {
    "type": "string"
  }
}

, .
,"anyOf"
"oneOf"
"allOf"

{
  "type": "string",
  "anyOf": [
    {"const": "user"},
    {"const": "manager" }
  ]
}

, .
,"$id" "$ref"RolesDictionaryDef.json:

{
"$id": http://archi-blair.com/schemas/RolesDictionaryDef.json#
}

1 $ref ( ):


"items": {
"type": "object",
"minLength": 1,
"properties": {
  "name": {
  "description": "  ",
  "type": "string"
   },
"description": {
  "description": " ",
  "type": "string"
 },
"dictionaryGroup": {
  "$ref": "RolesDictionaryDef.json#/definitions/roles"
    }
},
"additionalProperties": false
}

2 JSON. , $ref .
"$ref" "definitions""$ref": "#/definitions/roles" , «definitions»:

{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": " ",
"type": "object",
"properties": {
"dictionaries": {
   "description": "",
   "type": "array",
   "maxItems": 1,
   "items": {
      "type": "object",
      "minLength": 1,
      "properties": {
               "name": {
                  "description": " ",
                  "type": "string",
                  "enum": [
                     "Roles Dictionary"
                     ]
                 }
       "dictionaryGroups": {
             "$ref": "#/definitions/roles",
             "description": " "
          }
      },
 "additionalProperties": false
   }
  }
 },
 "additionalProperties": false,
     "definitions": {
          "roles": {
             "description": "",
             "type": "object",
             "properties": {
             "administrators": {
             "description": "",
             "type": "array",
             "uniqueItems": true,
             "items": {
             "type": "object",
             "properties": {
                   "name": {
                      "type": "string",
                      "enum": [
                         "administrator", 
                         "superuser"
                          ],
                        "enumNames": [
                          "", 
                          "-   "
                           ]
                         },
                    "enabled": {
                    "type": "boolean",
                    "default": true
                  }
              },
    "additionalProperties": false
      }
    }			
   },
  "additionalProperties": false
  }
 },
 "$id": "http://archi-blair.com/schemas/RolesDictionaryDef.json#"
}

, . $ref definitions.
"$ref"
.
"$ref": " #/definitions/roles"
"$ref": "RolesDictionaryDef.json#/definitions/roles"

, .
, .

We looked at the JSON schema keywords to describe the future structure of our messages in JSON format.

Here you can find more examples of using keywords.

Practice


When considering examples of completed JSON schemes, we will proceed similarly to examples of working with messages themselves in the JSON format. Those. we will use the visual representation in a tree and tabular form for our schemes of directories of roles, resources and authorities (operations), and with the text of the schemes I propose to read the interested readers on their own in git .

The following is a diagram for a role reference.


Figure 9. Example of JSON Schema for the role directory

As we see in the figure, the scheme is a JSON object and describes our message for transmitting the role directory in JSON, which was shown in Figure 4. In the current example, it can be shown how using JSON scheme An array object consisting of objects is described.

The schemes of the other two directories (authority and resources) are identical in structure to the scheme for the role directory, so I will not give them here, but I will give a scheme that combines all 3 directories.

Unfortunately, the scheme of the entire directory during expansion does not fit on the screen, so we will consider part of it.


Figure 10. An example of a JSON Schema directory that combines a directory of roles, permissions and resources

In the figure, we see that some of the objects in the array of directories are connected using the keyword "anyOf".

Also, perhaps, a tabular representation of the directory will be more visual.

Consider another important feature of our scheme:


Figure 11. An example JSON Schema of a directory combining a directory of roles, permissions and resources in a table view

From the figure we see that a combining directory does not duplicate code from previously developed directories of roles, permissions and resources, but uses the keyword "$ ref "

The directories considered in the examples are in the same directory, but, if necessary, this rule can not be observed, but can be placed in different directories, indicating the correct path to them when connecting. This feature is very useful, because it allows you to reuse previously created schemes, only connecting them to the desired structure.

This concludes my review of JSON and JSON Schema. I hope that the material presented here and the examples discussed will be useful in exploring the capabilities of JSON Schema.

Instead of a conclusion


I think it's time to take stock. So what can JSON Schema ultimately give us?

  1. It can make life easier for developers and improve code for validating JSON messages.
    In other words, it simplifies software support and integration.
  2. Allows you to develop services, working out the formats and composition of the data with a "reserve" for the future development of the system.
  3. Apply verification of documents in document-oriented, object-oriented databases.
  4. JSON-Schema can help save time testing and documenting the API.
  5. Simplify backward compatibility API support.
  6. Allows you to manage data streams.
  7. Flexible validation when generating JSON Schema in run-time with values ​​in "enum" obtained at the program execution stage.
    It can be used for a state machine or workflow with statuses in “enum” (application example fromTsdk and VolCh)
  8. JSON Schema can be applied in the implementation of DTO
    (example of use fromamarkevich)

Each of us decides “To be or not to be JSON Schema” in our IT projects. Above, I gave a list of what I consider to be the key advantage of using circuits, and for the sake of what it is already worth thinking about its application in projects.

Perhaps readers will want to help me continue this list?
I will be grateful :) I will

also give a list of links, in my opinion, useful for working with JSON and JSON Schema

  1. .
  2. .
  3. ().
  4. ( ).
  5. - JSON-Schema.
  6. JSON Schema
  7. JSON Schema , ( alemiks), angular ngx-schema-form, AJSF ( anotherpit).

And a link to the git repository, where you can get acquainted with the source files provided for review in this article: a repository with the source files of the examples .

System architect,
© Irina Blazhina

All Articles