Uttir
By Uttir 7 min read

How to Validate JSON Against a Schema (And Why You Should)

JSON Schema is the standard for describing the structure of JSON data. This guide covers what it is, when to use it, the basic syntax, and how to validate your data in your browser.

JSON Schema is a JSON document that describes the structure of another JSON document. It defines required fields, types, formats, ranges, and patterns. Validation: parse the data with JSON.parse, parse the schema, then walk both to check every constraint. The Uttir JSON Validator does basic syntactic validation in your browser. For full JSON Schema validation, the libraries ajv (JavaScript) and jsonschema (Python) are the standard choices.

JSON Schema is the standard for describing the structure of JSON data. It tells consumers what fields are required, what types each field should be, what ranges are valid, and what patterns strings should match. Validation against a schema catches bugs before they reach production. This guide covers the basics, the syntax, and how to validate in your browser.

What JSON Schema is

A JSON Schema is a JSON document that describes another JSON document. The schema declares:

  • What fields are required.
  • What type each field is (string, number, boolean, object, array, null).
  • For strings: minimum/maximum length, regex patterns, allowed formats (email, URI, date).
  • For numbers: minimum/maximum, integer-only, multiple-of.
  • For arrays: minimum/maximum length, what items should be, whether items must be unique.
  • For objects: what properties are required, what additional properties are allowed.

The schema is itself a JSON document. A schema for a "user" might look like:

{
  "type": "object",
  "required": ["id", "email", "age"],
  "properties": {
    "id": { "type": "integer", "minimum": 1 },
    "email": { "type": "string", "format": "email" },
    "age": { "type": "integer", "minimum": 0, "maximum": 150 },
    "name": { "type": "string" }
  }
}

This says: a user is an object with at least the fields id (positive integer), email (a valid email), and age (integer 0-150). The name field is optional but, if present, must be a string.

Why validate

Catch bugs early

The most common API bug: the client sends data the server did not expect. The server returns a 500 with a stack trace. The user is confused. A schema check on the client side (before the request) and the server side (before processing) catches this. The user sees a clear error: "Age must be a number between 0 and 150".

Document the API

A JSON Schema is a precise, machine-readable description of an API. It is better than prose documentation because it is testable: you can write a test that validates every example against the schema, ensuring the docs match the code.

Generate code

From a JSON Schema, you can generate TypeScript types, Java classes, Python dataclasses, Rust structs, and more. Tools like json-schema-to-typescript and quicktype do this automatically. The schema becomes the single source of truth for the data shape; the generated code is the implementation.

Validate third-party data

When ingesting data from an external API, a webhook, or a file upload, you do not control the data. A schema check ensures the data matches the expected shape before you try to use it.

The basic syntax

JSON Schema is versioned. The current standard is 2020-12 (also called "draft 2020-12"). The older drafts (draft-07, draft-06, draft-04) are still widely used. The syntax differs slightly between drafts; pick one and stick to it.

Type validation

The type keyword specifies the expected type:

  • "string" — text
  • "number" — number (integer or float)
  • "integer" — integer only (a subset of number)
  • "boolean" — true or false
  • "object" — JSON object (key-value pairs)
  • "array" — JSON array (list of values)
  • "null" — null value

You can allow multiple types with an array: "type": ["string", "null"] means the value can be a string or null.

String constraints

  • minLength, maxLength — character count
  • pattern — regex the string must match
  • format — predefined formats: email, uri, uuid, date, date-time, ipv4, ipv6, etc.
  • enum — list of allowed values

Number constraints

  • minimum, maximum — inclusive range
  • exclusiveMinimum, exclusiveMaximum — exclusive range
  • multipleOf — value must be a multiple of this

Object constraints

  • required — list of required property names
  • properties — schema for each named property
  • additionalProperties — true (allow), false (forbid), or a schema (validate the extras)
  • minProperties, maxProperties — count of properties

Array constraints

  • items — schema for each item (or a tuple of schemas for fixed positions)
  • minItems, maxItems — count of items
  • uniqueItems — all items must be unique

Composition

You can combine schemas:

  • allOf — must match all listed schemas
  • anyOf — must match at least one
  • oneOf — must match exactly one
  • not — must not match

An example: a complete schema

A schema for a blog post:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["title", "slug", "content", "author"],
  "properties": {
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "slug": {
      "type": "string",
      "pattern": "^[a-z0-9-]+$"
    },
    "content": {
      "type": "string",
      "minLength": 1
    },
    "author": {
      "type": "object",
      "required": ["id", "name"],
      "properties": {
        "id": { "type": "integer", "minimum": 1 },
        "name": { "type": "string", "minLength": 1 }
      }
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "uniqueItems": true,
      "maxItems": 10
    },
    "publishedAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "additionalProperties": false
}

This schema enforces: a non-empty title, a slug matching the standard slug pattern, a non-empty content, an author with id and name, a tags array of unique strings (max 10), and an optional published date in ISO 8601 format. additionalProperties: false forbids any field not listed.

How to validate

In JavaScript (with ajv)

The standard library is ajv (Another JSON Schema Validator). It is fast, supports all drafts, and has good error messages.

import Ajv from 'ajv';
const ajv = new Ajv();

const validate = ajv.compile(schema);
const valid = validate(data);

if (!valid) {
  console.log(validate.errors);
}

Ajv returns a list of error objects, each with a JSON Pointer to the offending field, a keyword, and a message. The errors are detailed enough to surface a useful error to the user.

In Python (with jsonschema)

The standard library is jsonschema:

from jsonschema import validate, ValidationError
import json

with open('schema.json') as f:
    schema = json.load(f)
with open('data.json') as f:
    data = json.load(f)

try:
    validate(instance=data, schema=schema)
except ValidationError as e:
    print(f"Validation error: {e.message}")
    print(f"Path: {list(e.path)}")

In the browser

You can run ajv in the browser directly. Load it as an ES module, compile the schema, validate the data. The whole flow runs locally; no upload is needed.

For a quick syntactic check (without a schema), the Uttir JSON Validator checks that the JSON is well-formed: balanced brackets, correct quoting, valid escapes. It does not enforce a schema, but it catches 80% of the bugs (malformed JSON, trailing commas, single quotes, etc.).

Common pitfalls

Forgetting required

JSON Schema's required is a list at the object level, not a per-property keyword. The common mistake: "name": { "type": "string", "required": true } is wrong. The correct syntax: "required": ["name"] at the object level.

Not handling null

By default, JSON Schema does not allow null unless you specify "type": "null" or include null in the type array. Many real-world APIs have nullable fields. The fix: "type": ["string", "null"] for each nullable field.

Not handling additional properties

By default, JSON Schema allows extra fields. A schema with {"type": "object", "properties": {"name": {"type": "string"}}} accepts {"name": "Ada", "age": 30} as valid. To forbid extras: "additionalProperties": false.

Format support varies

The format keyword has optional validation. Ajv includes formats for email, URI, UUID, date, etc. Other libraries may not. Always test your format with the validator you are using.

Confusing $ref and inline schemas

You can reference another schema with "$ref": "schemas/user.json". The reference is resolved at validation time. The pitfall: $ref in older drafts interacts weirdly with sibling keywords. Draft 2020-12 fixed most of these, but the older drafts are still common. If you are using $ref, specify the draft explicitly.

Where to use JSON Schema

API request and response validation

The most common use. Every API endpoint has a request schema and a response schema. Validate on both ends: the server validates the request before processing; the client validates the response before using it. The result: clearer error messages, faster debugging, and self-documenting APIs.

Configuration files

Many tools (VS Code, ESLint, Babel, etc.) use JSON Schema to validate configuration. The schema is shipped with the tool; users get autocomplete and error messages in their editor.

Form validation

Web forms can be described with JSON Schema and validated client-side. Libraries like @rjsf/core (React JSON Schema Form) generate a form UI from a schema and validate as the user types.

Data pipeline validation

ETL pipelines often validate the data at each step. A JSON Schema can be the "shape contract" between the producer and the consumer.

Generating fake data

Tools like json-schema-faker generate example data from a schema. Useful for testing and documentation.

When NOT to use JSON Schema

JSON Schema is for structured validation. It is the wrong tool for:

  • Content validation — "the text should make sense" or "the tone should be friendly". That is NLP, not schema.
  • Visual validation — "the page should look right". That is visual regression testing, not JSON Schema.
  • Performance validation — "the response should be under 100 ms". That is load testing.
  • Cross-reference validation — "this user_id should exist in the users table". That is a database check, not a JSON Schema check.

JSON Schema is great for shape. For other concerns, use a different tool.

Bottom line

JSON Schema is the standard for describing JSON data structure. It catches bugs, documents APIs, generates code, and validates third-party data. The basic syntax is small (type, required, properties, format). The standard libraries (ajv in JavaScript, jsonschema in Python) are fast and well-maintained. The Uttir JSON Validator handles the syntactic check in your browser. For full schema validation, run ajv in your build pipeline or in the browser via ES modules.

#json#json-schema#validation#developer-tools#api#how-to

New tools and guides, once a week

One short email when something new ships. No tracking, no images, unsubscribe with one click.