Understanding JSON Schema: Complete Validation Guide
Master JSON Schema for data validation. Learn schema syntax, validation techniques, and implementation across different programming languages.
Sarah Chen
• Senior Software EngineerSarah is a full-stack software engineer with 8 years of experience in API development, TypeScript, and data engineering. She has designed and maintained large-scale JSON processing pipelines and contributes in-depth technical guides on performance optimisation, schema design, Python data workflows, and backend integration patterns.
What is JSON Schema?
JSON Schema is a vocabulary for validating and describing JSON documents. It defines the structure, constraints, and validation rules for your JSON data.
Basic Schema Example
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "email"]
}
Schema Keywords
- type: Data type (string, number, object, array, boolean, null)
- required: Required properties
- properties: Object property definitions
- minimum/maximum: Number constraints
- minLength/maxLength: String length constraints
- pattern: Regex pattern for strings
- format: Predefined formats (email, uri, date, etc.)
Validation in JavaScript
import Ajv from 'ajv';
const ajv = new Ajv();
const schema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number', minimum: 0 }
},
required: ['name']
};
const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', age: 30 });
if (!valid) {
console.log(validate.errors);
}
Validation in Python
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name"]
}
data = {"name": "Alice", "age": 30}
try:
validate(instance=data, schema=schema)
print("Valid!")
except ValidationError as e:
print(f"Error: {e.message}")
Advanced Features
Schema References ($ref)
Reuse schema definitions to keep schemas DRY:
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zipCode": { "type": "string", "pattern": "^[0-9]{5}$" }
},
"required": ["street", "city", "zipCode"]
}
},
"type": "object",
"properties": {
"name": { "type": "string" },
"homeAddress": { "$ref": "#/$defs/address" },
"workAddress": { "$ref": "#/$defs/address" }
}
}
Schema Composition
allOf (AND) - Must match all schemas:{
"allOf": [
{ "type": "object", "properties": { "name": { "type": "string" } } },
{ "type": "object", "properties": { "age": { "type": "number" } } }
]
}
// Valid: { "name": "Alice", "age": 30 }
anyOf (OR) - Must match at least one schema:
{
"anyOf": [
{ "type": "string" },
{ "type": "number" }
]
}
// Valid: "hello" or 42
oneOf (XOR) - Must match exactly one schema:
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
// Valid: 5, 15 (multiple of 5 OR 3, but not both)
// Invalid: 15 (multiple of BOTH 5 and 3)
Conditional Schemas (if/then/else)
{
"type": "object",
"properties": {
"country": { "type": "string" },
"postalCode": { "type": "string" }
},
"if": {
"properties": { "country": { "const": "US" } }
},
"then": {
"properties": {
"postalCode": { "pattern": "^[0-9]{5}(-[0-9]{4})?$" }
}
},
"else": {
"properties": {
"postalCode": { "type": "string" }
}
}
}
Real-World Schema Examples
API Request Validation
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Create User Request",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "User's email address"
},
"password": {
"type": "string",
"minLength": 8,
"pattern": "^(?=.[A-Z])(?=.[a-z])(?=.[0-9])(?=.[!@#$%^&])",
"description": "Password must contain uppercase, lowercase, number, and special char"
},
"age": {
"type": "integer",
"minimum": 13,
"maximum": 120
},
"newsletter": {
"type": "boolean",
"default": false
}
},
"required": ["email", "password"],
"additionalProperties": false
}
Configuration File Validation
{
"type": "object",
"properties": {
"database": {
"type": "object",
"properties": {
"host": { "type": "string", "format": "hostname" },
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
"username": { "type": "string", "minLength": 1 },
"password": { "type": "string", "minLength": 8 },
"ssl": { "type": "boolean", "default": true }
},
"required": ["host", "port", "username", "password"]
},
"logging": {
"type": "object",
"properties": {
"level": {
"enum": ["debug", "info", "warn", "error"],
"default": "info"
},
"file": { "type": "string" }
}
}
},
"required": ["database"]
}
Schema Validation in Production
Express.js Middleware
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv();
addFormats(ajv);
function validateSchema(schema) {
const validate = ajv.compile(schema);
return (req, res, next) => {
const valid = validate(req.body);
if (!valid) {
return res.status(400).json({
error: 'Validation failed',
details: validate.errors
});
}
next();
};
}
// Usage
const userSchema = { / schema / };
app.post('/api/users', validateSchema(userSchema), createUser);
FastAPI (Python) Automatic Validation
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8, regex=r'^(?=.[A-Z])(?=.[a-z])(?=.[0-9])')
age: int = Field(ge=13, le=120)
newsletter: bool = False
app = FastAPI()
@app.post('/users')
async def create_user(user: UserCreate):
# user is automatically validated against schema
return {"email": user.email, "age": user.age}
Common Validation Patterns
Email Validation
{ "type": "string", "format": "email" }
URL Validation
{ "type": "string", "format": "uri" }
Date/Time Validation
{
"type": "string",
"format": "date-time" // ISO 8601: 2024-01-15T10:30:00Z
}
UUID Validation
{
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
}
Phone Number Validation
{
"type": "string",
"pattern": "^\+?[1-9]\d{1,14}$" // E.164 format
}
Benefits of JSON Schema
Best Practices
1. Use $schema and $id
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/user.json",
"title": "User"
}
2. Provide Descriptions
{
"properties": {
"timeout": {
"type": "integer",
"description": "Request timeout in milliseconds",
"minimum": 0,
"default": 5000
}
}
}
3. Use additionalProperties: false
Prevent unexpected properties:
{
"type": "object",
"properties": { "name": { "type": "string" } },
"additionalProperties": false // Reject extra fields
}
4. Version Your Schemas
When schemas evolve, version them:
schemas/
user-v1.json
user-v2.json
Conclusion
JSON Schema is essential for building reliable APIs and data pipelines. It provides validation, documentation, and contract enforcement in one machine-readable format. Whether you're building REST APIs, processing user input, or validating configuration files, JSON Schema ensures data quality and prevents runtime errors.
Key Takeaways:- Use schemas for all API endpoints
- Validate early (at API boundary)
- Share schemas between frontend/backend
- Auto-generate TypeScript/types from schemas
- Version schemas as they evolve
- additionalProperties: Control extra properties
Nested Schema Example
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
}
}
}
}
Array Validation
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
}
},
"minItems": 1,
"maxItems": 100
}
Best Practices
Schema Reusability
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"billingAddress": { "$ref": "#/$defs/address" },
"shippingAddress": { "$ref": "#/$defs/address" }
}
}
Conclusion
JSON Schema is essential for building robust APIs. It provides validation, documentation, and type safety for your JSON data!
Related Articles
What is JSON? Complete Guide for Beginners 2026
Learn what JSON is, its syntax, data types, and use cases. A comprehensive beginner-friendly guide to understanding JavaScript Object Notation.
JSON APIs and REST Services: Complete Development Guide
Learn to build and consume JSON-based REST APIs. Covers HTTP methods, authentication, best practices, and real-world implementation examples.
Common JSON Errors and How to Fix Them
Troubleshoot JSON syntax errors with this complete guide. Learn to identify and fix the most common JSON validation problems.