JSON Schema is a powerful tool for validating JSON data structures and ensuring data integrity across applications. This comprehensive guide covers JSON Schema generation, type detection, Draft-07 standards, and best practices for building robust API validation.
JSON Schema is a vocabulary that allows you to annotate and validate JSON documents. It provides a contract for what JSON data is required and how it should be structured, making it invaluable for API development, data validation, and documentation.
Think of JSON Schema as a blueprint for your JSON data. Just as architectural blueprints define building requirements, JSON Schema defines data requirements, ensuring consistency and correctness throughout your application.
Here's a simple JSON Schema for a user object:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/user.schema.json",
"title": "User",
"description": "A user in the system",
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "Unique identifier"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 20,
"pattern": "^[a-zA-Z0-9_]+$"
},
"email": {
"type": "string",
"format": "email"
},
"age": {
"type": "integer",
"minimum": 18,
"maximum": 120
}
},
"required": ["id", "username", "email"],
"additionalProperties": false
}
Every JSON Schema should include essential metadata:
JSON Schema supports seven primitive types:
1. String
{
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[A-Z][a-z]+$"
}
2. Number and Integer
{
"type": "number",
"minimum": 0,
"maximum": 100,
"multipleOf": 0.5
}
{
"type": "integer",
"minimum": 1,
"exclusiveMaximum": 1000
}
3. Boolean
{
"type": "boolean"
}
4. Null
{
"type": "null"
}
5. Object
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name"],
"additionalProperties": false
}
6. Array
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}
Properties can accept multiple types:
{
"type": ["string", "number"]
}
{
"type": ["object", "null"]
}
{
"type": "string",
"minLength": 5,
"maxLength": 50,
"pattern": "^[a-zA-Z0-9]+$",
"format": "email" // Built-in formats: email, uri, date-time, etc.
}
{
"type": "number",
"minimum": 0,
"maximum": 100,
"exclusiveMinimum": 0,
"exclusiveMaximum": 100,
"multipleOf": 5
}
{
"type": "object",
"properties": {
"name": { "type": "string" }
},
"required": ["name"],
"minProperties": 1,
"maxProperties": 10,
"additionalProperties": false,
"patternProperties": {
"^S_": { "type": "string" }
}
}
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true,
"contains": { "type": "string" }
}
Combine schemas using logical operators:
allOf (AND)
{
"allOf": [
{ "type": "object" },
{ "properties": { "name": { "type": "string" } } }
]
}
anyOf (OR)
{
"anyOf": [
{ "type": "string" },
{ "type": "number" }
]
}
oneOf (XOR)
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
not (NOT)
{
"not": { "type": "null" }
}
Apply schemas conditionally based on data:
{
"type": "object",
"properties": {
"country": { "type": "string" }
},
"if": {
"properties": { "country": { "const": "USA" } }
},
"then": {
"properties": {
"zipCode": {
"type": "string",
"pattern": "^[0-9]{5}(-[0-9]{4})?$"
}
}
},
"else": {
"properties": {
"postalCode": { "type": "string" }
}
}
}
Reuse schema definitions to avoid duplication:
{
"definitions": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["street", "city", "country"]
}
},
"type": "object",
"properties": {
"billingAddress": { "$ref": "#/definitions/address" },
"shippingAddress": { "$ref": "#/definitions/address" }
}
}
When generating schemas from JSON samples, tools analyze values to infer types:
// Input JSON
{
"name": "John Doe",
"age": 30,
"active": true,
"tags": ["developer", "javascript"],
"settings": {
"theme": "dark"
}
}
// Generated Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" },
"active": { "type": "boolean" },
"tags": {
"type": "array",
"items": { "type": "string" }
},
"settings": {
"type": "object",
"properties": {
"theme": { "type": "string" }
},
"required": ["theme"]
}
},
"required": ["name", "age", "active", "tags", "settings"]
}
Advanced generators can detect patterns and add validation:
// Email detection
{
"email": "[email protected]"
}
// Schema: { "type": "string", "format": "email" }
// URL detection
{
"website": "https://example.com"
}
// Schema: { "type": "string", "format": "uri" }
// Date detection
{
"createdAt": "2026-03-12T10:00:00Z"
}
// Schema: { "type": "string", "format": "date-time" }
Analyze multiple samples to infer constraints:
// From samples: [5, 10, 15, 20]
{
"type": "integer",
"minimum": 5,
"maximum": 20,
"multipleOf": 5
}
// From samples: ["abc", "def", "ghi"]
{
"type": "string",
"minLength": 3,
"maxLength": 3,
"pattern": "^[a-z]{3}$"
}
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv();
addFormats(ajv);
const schema = {
type: "object",
properties: {
name: { type: "string" },
age: { type: "integer", minimum: 0 }
},
required: ["name", "age"]
};
const validate = ajv.compile(schema);
const valid = validate({ name: "John", age: 30 });
console.log(valid); // true
const invalid = validate({ name: "John" });
console.log(invalid); // false
console.log(validate.errors);
// [{ instancePath: '', schemaPath: '#/required', ... }]
import Ajv from 'ajv';
import ajvErrors from 'ajv-errors';
const ajv = new Ajv({ allErrors: true });
ajvErrors(ajv);
const schema = {
type: "object",
properties: {
email: {
type: "string",
format: "email"
}
},
required: ["email"],
errorMessage: {
required: {
email: "Email address is required"
},
properties: {
email: "Must be a valid email address"
}
}
};
// Express.js middleware
const validateRequest = (schema) => {
return (req, res, next) => {
const validate = ajv.compile(schema);
const valid = validate(req.body);
if (!valid) {
return res.status(400).json({
error: 'Validation failed',
details: validate.errors
});
}
next();
};
};
app.post('/users', validateRequest(userSchema), (req, res) => {
// Handle validated request
});
openapi: 3.0.0
paths:
/users:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
name:
type: string
minLength: 1
email:
type: string
format: email
required:
- name
- email
{
"title": "User Profile",
"description": "Represents a user profile in the system",
"type": "object",
"properties": {
"username": {
"type": "string",
"description": "Unique username for login",
"examples": ["john_doe", "jane_smith"]
}
}
}
{
"type": "object",
"properties": {
"password": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"pattern": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$"
}
}
}
// Strict mode (recommended for APIs)
{
"type": "object",
"properties": { ... },
"additionalProperties": false
}
// Allow additional properties
{
"type": "object",
"properties": { ... },
"additionalProperties": true
}
// Typed additional properties
{
"type": "object",
"properties": { ... },
"additionalProperties": { "type": "string" }
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://api.example.com/schemas/user/v1.0.0",
"version": "1.0.0",
"title": "User Schema"
}
{
"type": "string",
"format": "email",
"examples": [
"[email protected]",
"[email protected]"
]
}
const configSchema = {
type: "object",
properties: {
server: {
type: "object",
properties: {
port: { type: "integer", minimum: 1024, maximum: 65535 },
host: { type: "string", format: "hostname" }
},
required: ["port", "host"]
},
database: {
type: "object",
properties: {
url: { type: "string", format: "uri" },
pool: {
type: "object",
properties: {
min: { type: "integer", minimum: 0 },
max: { type: "integer", minimum: 1 }
}
}
},
required: ["url"]
}
},
required: ["server", "database"]
};
const registrationSchema = {
type: "object",
properties: {
username: {
type: "string",
minLength: 3,
maxLength: 20,
pattern: "^[a-zA-Z0-9_]+$"
},
email: {
type: "string",
format: "email"
},
password: {
type: "string",
minLength: 8
},
confirmPassword: {
type: "string",
const: { "$data": "1/password" }
},
terms: {
type: "boolean",
const: true
}
},
required: ["username", "email", "password", "confirmPassword", "terms"]
};
const migrationSchema = {
type: "array",
items: {
type: "object",
properties: {
id: { type: "integer" },
oldValue: { type: "string" },
newValue: { type: "string" }
},
required: ["id", "newValue"]
},
minItems: 1
};
If validation fails unexpectedly, check for:
For large schemas:
Make errors user-friendly with custom messages:
import Ajv from 'ajv';
import ajvErrors from 'ajv-errors';
const ajv = new Ajv({ allErrors: true });
ajvErrors(ajv);
// Add custom error messages to schema
JSON Schema is an essential tool for modern API development and data validation. By generating schemas from JSON data, implementing proper validation, and following best practices, you can ensure data integrity, improve documentation, and catch errors early in development.
Use QuickUtil.dev's JSON Schema Generator to quickly create Draft-07 compliant schemas from your JSON data, complete with type detection and validation rules.
JSON Schema is a declarative language that allows you to annotate and validate JSON documents. It defines the structure, data types, and validation rules for JSON data using a schema document.
Use a JSON Schema generator tool to analyze your JSON data. The tool detects types, patterns, and structure to create a schema with validation rules, type definitions, and constraints automatically.
Draft-07 is the widely-adopted JSON Schema specification that includes features like if/then/else conditionals, readOnly/writeOnly properties, and improved schema composition. It's the current stable version.
JSON Schema validation ensures data integrity, provides clear API contracts, enables automatic documentation, catches errors early, and improves code reliability by validating data structure and types.
Use JSON Schema validators like Ajv, jsonschema, or joi. These libraries compare your JSON data against the schema and return validation results with detailed error messages for mismatches.
JSON Schema validates: string, number, integer, boolean, null, object, and array types. Each type supports specific validation keywords like minLength, maximum, pattern, required, and more.
Yes, JSON Schema is excellent for API documentation. It provides machine-readable contracts that can be used with OpenAPI/Swagger, generates documentation automatically, and ensures consistency across endpoints.
JSON Schema validates at runtime and is language-agnostic, while TypeScript provides compile-time type checking for JavaScript. Both can work together: generate TypeScript from Schema or Schema from TypeScript.
Create Draft-07 compliant JSON Schemas from your JSON data automatically. Validate APIs, ensure data integrity, and improve documentation.
Try the JSON Schema Generator Now