Skip to content

JSON Schema Basics

Introduction

JSON has like XSL for XML a schema to validate de content of a JSON-file. Schema files are name regularly named *.schema.json.
The json-schema.org site has the detailed information.

Actually validation is needed while:

  • Developing using an IDE (JetBrains/CLion)
  • Command line unit testing (Python)
  • In the code at runtime (C++)

For each a solution given including installation or configuration instructions.

Validation Example

This example uses references to other schema files for types or objects.
For the example the files are structured accordingly.

<project-root>
  ├─ json (*.schema.json)
  └─ schema (test.*.json)

The File to Validate

Simple json-file named test.customer.json of customer to ship products. Name of the file is important for the IDE (JetBrains) file mappings.

{
    "name": {
        "first": "Prins",
        "middle": "van",
        "last": "Oranje"
    },
    "billing_address": {
        "street_address": "Noordeinde 68",
        "postal_code": "2514GL",
        "city": "'s-Gravenhage",
        "state": "Zuid-Holland"
    },
    "shipping_address": {
        "street_address": "Molenstraat 27",
        "postal_code": "2513BJ",
        "city": "'s-Gravenhage",
        "state": "Zuid-Hoilland"
    },
    "parcel_size": {
        "height": 200,
        "width": 80,
        "depth": 30
    }
}

Schema Files for Validation

Multiple schema files are used to demonstrate a way to organize and reuse schemas in a structured way.

Definitions Schema

This file contains specific individual types and are referenced by multiple schema files.
It is also subject to a schema itself and in this case http://json-schema.org/draft-07/schema#.

{
    "$id": "defs",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20
        },
        "middleName": {
            "type": "string",
            "minLength": 0,
            "maxLength": 15
        },
        "lastName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30
        },
        "cityName": {
            "type": "string",
            "pattern": "^.{1,40}$"
        },
        "stateName": {
            "type": "string",
            "pattern": "^.{1,40}$"
        },
        "parcelSizeHeight": {
            "type": "number",
            "maximum": 210,
            "minimum": 30
        },
        "parcelSizeWidth": {
            "type": "number",
            "maximum": 85,
            "minimum": 30
        },
        "parcelSizeDepth": {
            "type": "number",
            "maximum": 250,
            "minimum": 30
        },
        "postalCode": {
            "type": "string",
            "pattern": "^[1-9][0-9]{3}[A-Z]{2}$"
        }
    }
}

Address Schema

This file describes an object and is referenced in full.
The file also references defs.schema.json for individual types.

{
    "$id": "address",
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "street_address": {
            "type": "string"
        },
        "postal_code": {
            "$ref": "defs.schema.json#/definitions/postalCode"
        },
        "city": {
            "$ref": "defs.schema.json#/definitions/cityName"
        },
        "state": {
            "$ref": "defs.schema.json#/definitions/stateName"
        }
    },
    "required": [
        "street_address",
        "postal_code",
        "city",
        "state"
    ]
}

Customer Schema

This file uses a mix of objects like name which is locally defined.
Objects bgilling_address and shipping_address are externally defined.

In order for the validator (python3-jsonschema) to find the referenced schemas locally a full path file-url is needed.

{
    "$id": "file://<full-dir-from-root>/schema/customer.schema.json",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "name": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "first": {
                    "$ref": "defs.schema.json#/definitions/firstName"
                },
                "middle": {
                    "$ref": "defs.schema.json#/definitions/middleName"
                },
                "last": {
                    "$ref": "defs.schema.json#/definitions/lastName"
                }
            },
            "required": [
                "first",
                "middle",
                "last"
            ]
        },
        "shipping_address": {
            "$ref": "address.schema.json"
        },
        "billing_address": {
            "$ref": "address.schema.json"
        },
        "parcel_size": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "height": {
                    "$ref": "defs.schema.json#/definitions/parcelSizeHeight"
                },
                "width": {
                    "$ref": "defs.schema.json#/definitions/parcelSizeWidth"
                },
                "depth": {
                    "$ref": "defs.schema.json#/definitions/parcelSizeDepth"
                }
            }
        }
    },
    "required": [
        "name",
        "shipping_address",
        "billing_address",
        "parcel_size"
    ]
}

Actual Validation Options

Command-line

Python has an application which can be installed by installing package python3-jsonschema.

For debian with the apt package manager this is.

sudo apt install python3-jsonschema`

When done the command jsonschema is available and jsonschema --help tells that for our purpose

jsonschema -i <project-root>/json/test.customer.json <project-root>/schema/customer.schema.json

IDE (JetBrain/CLion)

In JetBrains products json-schemas can be configured using file mappings allowing wildcards. Since the schema is also a JSON-file it is also subject to a schema itself and this is configured too. In the JetBrains product like CLion go to "Settings | Languages & Frameworks | Schemas & DTDs | JSON Schema Mappings".

Add an external schema called "JSON Schema version 7" using URL http://json-schema.org/draft-07/schema and add file pattern *.schema.json.
Add another one called "Customer Data" using file <project-root>/schema/customer.schema.json and file pattern *.customer.json.

After this the file `test.customer.json in the editor is automatically validate. In the editor itself and in "Problems" tab the validation errors are reported.

Runtime in C++ Code

At the time of writing a working version is at GitHub pboettch/json-schema-validator

Add the file cmake/nlohmann_jsonConfig.cmake in the project with the following content.

# FetchContent added in CMake 3.11, downloads during the configure step.
include(FetchContent)
# Import Json library.
FetchContent_Declare(
    json
    GIT_REPOSITORY https://github.com/nlohmann/json
    GIT_TAG v3.8.0
    )
# Adds nlohmann_json::nlohmann_json
FetchContent_MakeAvailable(json)

Insert the following into the main CMakeLists.txt file to make it find the cmake/nlohmann_jsonConfig.cmake file.

# Make it so our own packages are found.
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")

As of writing the GitHub nlohmann_json version is at v3.11.2.

It seems the library does not handle file URLs (file:///home/user/schema) but only HTTP of HTTPS protocols.