JSON Schema: How to Validate the Shape of Your JSON

By Sheng Pang · Published · 4 min read

A JSON validator tells you whether text is well formed. It does not tell you whether the text is the right shape: that age is a number, that email is present, that status is one of three allowed words. JSON Schema is the standard for describing that shape and checking documents against it. It is used by OpenAPI, by editors for autocomplete, and by thousands of APIs to reject bad input before it reaches business logic.

A schema is itself JSON

Here is a schema for a user record:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "User",
  "type": "object",
  "properties": {
    "id":     { "type": "string", "format": "uuid" },
    "name":   { "type": "string", "minLength": 1 },
    "email":  { "type": "string", "format": "email" },
    "age":    { "type": "integer", "minimum": 0, "maximum": 150 },
    "role":   { "type": "string", "enum": ["admin", "editor", "viewer"] },
    "tags":   { "type": "array", "items": { "type": "string" }, "uniqueItems": true }
  },
  "required": ["id", "name", "email"],
  "additionalProperties": false
}

And a document that passes:

{
  "id": "0192a7b3-4c1e-7d2f-9a3b-8c7d6e5f4a3b",
  "name": "Ada",
  "email": "ada@example.com",
  "role": "admin",
  "tags": ["founder"]
}

Remove email and validation fails with "required property email is missing". Set role to "owner" and it fails the enum. Add a nickname field and it fails because additional properties are forbidden.

The keywords you will use most

  • type: one of object, array, string, number, integer, boolean, null. Can be a list to allow several.
  • properties: a schema for each named key of an object.
  • required: the keys that must be present. Everything else is optional by default.
  • additionalProperties: set to false to reject unknown keys, which catches typos.
  • items: the schema every array element must match.
  • enum: an exact list of allowed values.
  • minimum, maximum, minLength, maxLength, minItems: range limits.
  • pattern: a regular expression a string must match. The UUID regex from our UUID validation guide works here.
  • format: named formats such as email, uri, date-time, uuid. Validators may treat these as hints only unless you enable format checking.

Reusing pieces with $ref

{
  "$defs": {
    "address": {
      "type": "object",
      "properties": { "city": { "type": "string" }, "zip": { "type": "string" } },
      "required": ["city"]
    }
  },
  "type": "object",
  "properties": {
    "home": { "$ref": "#/$defs/address" },
    "work": { "$ref": "#/$defs/address" }
  }
}

Define a sub schema once under $defs and point at it. Refs can also target other files or URLs.

Combining schemas

oneOf, anyOf and allOf take lists of schemas. A common use is a discriminated union: a payment is either a card with a number or a bank transfer with an IBAN, never both. if, then and else handle conditional rules such as "if country is US then zip is required".

Running validation

JavaScript with Ajv, the most used validator:

import Ajv from "ajv";
import addFormats from "ajv-formats";

const ajv = addFormats(new Ajv());
const validate = ajv.compile(schema);
if (!validate(data)) console.log(validate.errors);

Python:

from jsonschema import validate, ValidationError
try:
    validate(instance=data, schema=schema)
except ValidationError as e:
    print(e.message)

Command line, once you have a schema and a file:

npx ajv-cli validate -s schema.json -d data.json

Where it pays off

  • API input. Reject malformed requests with a precise error before any code runs.
  • Config files. Point your editor at a schema and get autocomplete and red squiggles. VS Code does this through the $schema key or its settings.
  • Contracts between teams. A schema is a precise, testable description of what a service accepts and returns. OpenAPI documents embed JSON Schema for exactly this.
  • Test fixtures. Validate every fixture in CI so that a change to the data shape fails loudly.

Drafts and versions

JSON Schema has gone through several drafts. Draft 2020-12 is current and what new work should use. Draft 7 is still very common because OpenAPI 3.0 was based on it. The keywords above work the same in both. Always set $schema at the top of your file so tools know which rules to apply.

Before writing a schema, make sure your sample documents are valid JSON in the first place. Our JSON formatter will catch syntax errors so you are only debugging shape problems.

← Back to all articles