The Problem JSON Schema Solves
APIs receive bad data. A field expected to be an integer arrives as a string. A required field is missing. An email field contains "not-an-email". Without validation, these problems surface deep inside your application logic — often as cryptic runtime errors, not clear validation messages.
JSON Schema is the industry-standard solution: a declarative language for describing exactly what valid JSON should look like. Write the schema once, validate anywhere.
What Is a JSON Schema?
A JSON Schema is a JSON document that describes the structure and constraints of another JSON document.
``json
{
"type": "object",
"required": ["id", "email"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"email": { "type": "string", "format": "email" }
},
"additionalProperties": false
}
`
This schema accepts objects with an integer id (at least 1) and a valid email string. Any extra fields are rejected.
The Draft Versions
JSON Schema has several published drafts. Draft-07 is the most important to know:
- Used by OpenAPI 3.0 (the Swagger standard for REST APIs)
- Supported by Ajv (JavaScript), jsonschema (Python), and most tooling
- Added if
/then/else conditional validation - Still the most widely deployed version in production
Draft 2020-12 is newer but draft-07 is what you'll encounter in existing codebases and tooling.
Core Keywords
Types
<code>json
<p>{ "type": "string" }</p>
<p>{ "type": ["string", "null"] }</p>
</code>
Types: string, number, integer, boolean, null, array, object. An array of types means "any of these".
String Validation
<code>json
<p>{</p>
<p>"type": "string",</p>
<p>"minLength": 3,</p>
<p>"maxLength": 50,</p>
<p>"pattern": "^[a-z0-9_]+$",</p>
<p>"format": "email"</p>
<p>}</p>
</code>
format options: email, uri, date (YYYY-MM-DD), date-time, ipv4, hostname.
Number Validation
<code>json
<p>{</p>
<p>"type": "number",</p>
<p>"minimum": 0,</p>
<p>"maximum": 100,</p>
<p>"multipleOf": 0.01</p>
<p>}</p>
</code>
Use exclusiveMinimum/exclusiveMaximum for strict bounds (in draft-07, these take numeric values).
Array Validation
<code>json
<p>{</p>
<p>"type": "array",</p>
<p>"items": { "type": "string" },</p>
<p>"minItems": 1,</p>
<p>"maxItems": 20,</p>
<p>"uniqueItems": true</p>
<p>}</p>
</code>
When items is a schema, every element must match it. For tuple validation (different schema per position), set items to an array of schemas.
Object Composition
<code>json
<p>{</p>
<p>"type": "object",</p>
<p>"required": ["name"],</p>
<p>"properties": {</p>
<p>"name": { "type": "string" },</p>
<p>"role": { "type": "string", "enum": ["admin", "user"] }</p>
<p>},</p>
<p>"additionalProperties": false</p>
<p>}</p>
</code>
required lists mandatory keys. additionalProperties: false rejects undeclared keys.
Schema Composition
allOf, anyOf, oneOf
- allOf
— must be valid against every schema (AND) - anyOf
— must be valid against at least one schema (OR) - oneOf
— must be valid against exactly one schema
<code>json
<p>{</p>
<p>"oneOf": [</p>
<p>{ "properties": { "type": { "const": "circle" } }, "required": ["radius"] },</p>
<p>{ "properties": { "type": { "const": "rect" } }, "required": ["width", "height"] }</p>
<p>]</p>
<p>}</p>
</code>
This is a discriminated union: exactly one branch matches based on the type field.
Reusable Definitions with $ref
<code>json
<p>{</p>
<p>"$defs": {</p>
<p>"Address": {</p>
<p>"type": "object",</p>
<p>"required": ["street", "city"],</p>
<p>"properties": {</p>
<p>"street": { "type": "string" },</p>
<p>"city": { "type": "string" },</p>
<p>"zip": { "type": "string", "pattern": "^\\d{5}$" }</p>
<p>}</p>
<p>}</p>
<p>},</p>
<p>"type": "object",</p>
<p>"properties": {</p>
<p>"billing": { "$ref": "#/$defs/Address" },</p>
<p>"shipping": { "$ref": "#/$defs/Address" }</p>
<p>}</p>
<p>}</p>
</code>
Define a schema once in $defs, reference it anywhere with $ref. Eliminates duplication.
Conditional Validation with if/then/else
<code>json
<p>{</p>
<p>"if": { "properties": { "plan": { "const": "paid" } }, "required": ["plan"] },</p>
<p>"then": { "required": ["paymentMethod"] },</p>
<p>"else": {}</p>
<p>}</p>
</code>
If plan equals "paid", then paymentMethod is required. If plan is anything else, no additional constraint applies.
Validate in Your Browser
You can test JSON Schema immediately — no installation needed. Paste your schema on the left, paste your JSON on the right, and see clear path-based error messages (e.g. $.user.address.zip) in real time:
JSON Schema Validator — SnappyTools
Entirely client-side — your data never leaves the browser. Safe for API payloads with credentials or private configuration.
Validate in Code
JavaScript (Node.js):
<code>bash
<p>npm install ajv ajv-formats</p>
</code>
`js
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv();
addFormats(ajv);
const validate = ajv.compile(schema);
if (!validate(data)) {
console.error(validate.errors);
}
`
Python:
<code>bash
<p>pip install jsonschema</p>
</code>
`python
from jsonschema import validate, ValidationError
try:
validate(instance=data, schema=schema)
except ValidationError as e:
print(e.message, list(e.absolute_path))
`
Schemas written for the browser tool work identically in both libraries — same standard, no rewriting.
Common Errors Explained
"Additional property not allowed" — your JSON has a field not listed in properties, and the schema has additionalProperties: false. Add the field to the schema or remove it from the JSON.
"Missing required property" — a field listed in required is absent from the JSON. Either add it or remove it from required.
"Expected type integer, got string" — the JSON field is a quoted string ("42") where the schema expects a number (42). Remove the quotes.
"Value must match exactly one schema in oneOf (matched 0)" — the data doesn't match any branch. Check the discriminator field and the branch conditions.
Summary
| Keyword | Purpose |
|---------|---------|
| type | Restrict to a JSON type |
| properties + required | Define expected object fields |
| additionalProperties | Control unknown fields |
| enum / const | Restrict to fixed values |
| minLength / maxLength | String length bounds |
| minimum / maximum | Numeric bounds |
| items | Array element schema |
| allOf / anyOf / oneOf | Schema composition |
| $ref + $defs | Reusable definitions |
| if / then / else` | Conditional validation |
JSON Schema is the cheapest way to catch data problems before they reach your application logic. Write it once, validate everywhere.
Originally published at https://snappytools.app/json-schema-validator/