正在加载,请稍候…

JSON Schema: How to Validate JSON Data with Examples

Learn JSON Schema from scratch — defining types, required fields, nested objects, arrays, enums, and patterns. Includes validators, examples, and common validation errors.

JSON Schema: Validate and Document Your JSON Data

JSON Schema is a vocabulary for annotating and validating JSON documents. It describes the structure of your data — which fields are required, what types they must be, and what constraints they must satisfy. Think of it as TypeScript for your runtime data.

JSON Schema is used for:

  • Validating API request/response bodies
  • Documenting data structures in OpenAPI specs
  • Generating forms from schema definitions
  • Validating configuration files
  • Code generation (TypeScript types from schema)

Basic Schema Structure

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/schemas/user.json",
  "title": "User",
  "description": "A registered user in the system",
  "type": "object"
}
Keyword Purpose
$schema Which draft of JSON Schema to use
$id Unique identifier for this schema
title Human-readable name
description Documentation
type Data type constraint

Primitive Types

{ "type": "string" }
{ "type": "number" }
{ "type": "integer" }
{ "type": "boolean" }
{ "type": "null" }
{ "type": ["string", "null"] }

String Constraints

{
  "type": "string",
  "minLength": 1,
  "maxLength": 100,
  "pattern": "^[a-zA-Z0-9_]+
quot;, "format": "email" }

Format values (validation depends on the validator library):

Format Validates
"email" Email addresses
"uri" URIs
"date" YYYY-MM-DD
"time" HH:MM:SS
"date-time" ISO 8601 datetime
"uuid" UUID v1–v5
"ipv4" IPv4 address
"ipv6" IPv6 address
"hostname" DNS hostname

Number Constraints

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMinimum": 0,
  "multipleOf": 0.01
}

Objects

{
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "description": "Unique user ID"
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "role": {
      "type": "string",
      "enum": ["admin", "editor", "viewer"]
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required": ["id", "name", "email"],
  "additionalProperties": false
}

Key keywords:

  • properties: Defines the schema for each key
  • required: Array of keys that must be present
  • additionalProperties: false: Reject extra fields not in properties
  • additionalProperties: { "type": "string" }: Allow extra fields but constrain their type

Property Counts

{
  "type": "object",
  "minProperties": 1,
  "maxProperties": 10
}

Arrays

{
  "type": "array",
  "items": { "type": "string" },
  "minItems": 1,
  "maxItems": 100,
  "uniqueItems": true
}

Tuple Validation (Fixed Length Array)

{
  "type": "array",
  "prefixItems": [
    { "type": "string" },
    { "type": "number" },
    { "type": "boolean" }
  ],
  "items": false
}

This validates ["Alice", 30, true] but rejects ["Alice", 30, true, "extra"].

Nested Schemas

{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "address": {
          "type": "object",
          "properties": {
            "street": { "type": "string" },
            "city": { "type": "string" },
            "country": { "type": "string", "minLength": 2, "maxLength": 2 }
          },
          "required": ["street", "city", "country"]
        }
      },
      "required": ["name"]
    },
    "tags": {
      "type": "array",
      "items": { "type": "string", "minLength": 1 },
      "uniqueItems": true
    }
  }
}

Reusing Schemas with $ref

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$defs": {
    "Address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" }
      },
      "required": ["street", "city"]
    },
    "User": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "homeAddress": { "$ref": "#/$defs/Address" },
        "workAddress": { "$ref": "#/$defs/Address" }
      }
    }
  },
  "$ref": "#/$defs/User"
}

$defs (formerly definitions) holds reusable subschemas. $ref references them by JSON Pointer.

Combining Schemas

// oneOf: exactly one must match
{
  "oneOf": [
    { "type": "string" },
    { "type": "integer" }
  ]
}

// anyOf: one or more must match
{
  "anyOf": [
    { "type": "string", "format": "email" },
    { "type": "string", "format": "uri" }
  ]
}

// allOf: all must match (useful for composition/inheritance)
{
  "allOf": [
    { "$ref": "#/$defs/BaseUser" },
    {
      "properties": {
        "adminLevel": { "type": "integer", "minimum": 1, "maximum": 3 }
      },
      "required": ["adminLevel"]
    }
  ]
}

// not: must NOT match
{
  "not": { "type": "string" }
}

Conditional Validation (if/then/else)

{
  "type": "object",
  "properties": {
    "type": { "type": "string", "enum": ["individual", "business"] },
    "name": { "type": "string" },
    "companyName": { "type": "string" },
    "vatNumber": { "type": "string" }
  },
  "if": {
    "properties": { "type": { "const": "business" } }
  },
  "then": {
    "required": ["companyName", "vatNumber"]
  },
  "else": {
    "required": ["name"]
  }
}

Validating in JavaScript

AJV (Recommended)

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

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);  // adds email, date-time, uri, etc.

const schema = {
  type: 'object',
  properties: {
    name: { type: 'string', minLength: 1 },
    email: { type: 'string', format: 'email' },
    age: { type: 'integer', minimum: 0, maximum: 150 },
  },
  required: ['name', 'email'],
  additionalProperties: false,
};

const validate = ajv.compile(schema);

const data = { name: 'Alice', email: 'alice@example.com', age: 30 };
const valid = validate(data);

if (!valid) {
  console.log(validate.errors);
  // [{
  //   instancePath: '/email',
  //   message: 'must match format "email"',
  //   ...
  // }]
}

Zod (TypeScript-first, more common in modern apps)

import { z } from 'zod';

const UserSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(0).max(150).optional(),
  role: z.enum(['admin', 'editor', 'viewer']),
});

type User = z.infer<typeof UserSchema>;  // derives TypeScript type

const result = UserSchema.safeParse({ name: 'Alice', email: 'bad-email', role: 'admin' });
if (!result.success) {
  result.error.issues.forEach(issue => {
    console.log(issue.path, issue.message);
    // ['email'] 'Invalid email'
  });
}

Generating JSON Schema from Zod

import { zodToJsonSchema } from 'zod-to-json-schema';

const jsonSchema = zodToJsonSchema(UserSchema, 'User');
// produces standard JSON Schema from Zod definition

JSON Schema in OpenAPI

# openapi.yaml
paths:
  /users:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserInput'

components:
  schemas:
    CreateUserInput:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        email:
          type: string
          format: email
      required: [name, email]
      additionalProperties: false

→ Explore and validate JSON data structures in the browser with the JSON Viewer.