Your backend says it returns { "price": 29.99 }. Your frontend displays it as a number. One day, a backend developer changes it to { "price": "29.99" } — a string. Your UI breaks. Nobody notices until a user reports it.
This is an API contract violation, and it happens more than it should. JSON Schema is the tool that catches it automatically.
What Is JSON Schema?
JSON Schema is a vocabulary for describing the structure of JSON data. You write a schema — itself a JSON document — that defines what fields exist, what their types are, which ones are required, and what constraints they must satisfy. You can then validate any JSON object against this schema programmatically.
Think of it as a type system for your API responses.
A Simple Example
Suppose your API returns a user object:
{
"id": 42,
"name": "Maria Santos",
"email": "maria@example.com",
"role": "admin",
"created_at": "2025-11-01T09:00:00Z"
}
Here's the JSON Schema that describes it:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "name", "email", "role", "created_at"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 1 },
"email": { "type": "string", "format": "email" },
"role": { "type": "string", "enum": ["admin", "user", "guest"] },
"created_at": { "type": "string", "format": "date-time" }
},
"additionalProperties": false
}
This schema enforces:
idmust be an integer (not a string)emailmust be a valid email formatrolemust be one of three specific values- All five fields are required
- No extra fields are allowed (
additionalProperties: false)
Core Schema Keywords
| Keyword | What It Does |
|---|---|
type | Specifies data type: string, number, integer, boolean, array, object, null |
required | Array of property names that must be present |
properties | Defines the schema for each property of an object |
enum | Value must be one of a specific list |
minimum / maximum | Numeric range constraints |
minLength / maxLength | String length constraints |
pattern | String must match a regex pattern |
items | Schema for items in an array |
format | Semantic format hints: email, date-time, uri, uuid |
Validating Arrays
For a paginated list response:
{
"type": "object",
"required": ["data", "total", "page", "per_page"],
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
}
}
},
"total": { "type": "integer", "minimum": 0 },
"page": { "type": "integer", "minimum": 1 },
"per_page": { "type": "integer", "minimum": 1, "maximum": 100 }
}
}
Using JSON Schema in JavaScript
The most popular validator for JavaScript is Ajv:
npm install ajv
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv();
addFormats(ajv);
const schema = {
type: 'object',
required: ['id', 'name', 'email'],
properties: {
id: { type: 'integer' },
name: { type: 'string' },
email: { type: 'string', format: 'email' }
}
};
const validate = ajv.compile(schema);
const data = await fetch('/api/users/1').then(r => r.json());
if (!validate(data)) {
console.error('API response invalid:', validate.errors);
}
Using JSON Schema in PHP (Laravel)
composer require opis/json-schema
use Opis\JsonSchema\Validator;
use Opis\JsonSchema\Helper;
$validator = new Validator();
$schema = Helper::toJSON('{
"type": "object",
"required": ["id", "name"],
"properties": {
"id": {"type": "integer"},
"name": {"type": "string"}
}
}');
$result = $validator->validate($data, $schema);
if (!$result->isValid()) {
// handle validation failure
}
Where to Apply Schema Validation
- In API tests: Assert that every response matches the schema, not just the status code
- In integration tests: Catch contract drift between services
- At runtime (optional): Validate responses from third-party APIs before you process them
- In documentation: JSON Schema is the basis of OpenAPI — if you write schemas, you're already halfway to full API documentation
JSON Schema and Mock APIs
When you're building mock API responses, writing the JSON Schema first is a powerful technique. Define the contract, mock it with the schema-compliant response, then share the schema with both the frontend and backend teams. Everyone builds to the same spec. When the real implementation is ready, run your schema tests against it to verify nothing drifted.
Conclusion
JSON Schema turns informal API contracts into enforceable specifications. It takes 10 minutes to write a schema for your most important endpoints, and it will save you hours of debugging when a response changes unexpectedly. Start with your most critical endpoints — authentication, payments, user data — and expand from there.