JSON Schema Primer: Validate API Payloads Before They Break Your App

5 81
calendar_todayschedule5 min read

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

`json
{


"type": "string",


"minLength": 3,


"maxLength": 50,


"pattern": "^[a-z0-9_]+$",</p> <p>"format": "email"</p> <p>}</p> </code>`<code> </code>format<code> options: </code>email<code>, </code>uri<code>, </code>date<code> (YYYY-MM-DD), </code>date-time<code>, </code>ipv4<code>, </code>hostname<code>. <h3>Number Validation</h3> </code>`<code>json <p>{</p> <p>"type": "number",</p> <p>"minimum": 0,</p> <p>"maximum": 100,</p> <p>"multipleOf": 0.01</p> <p>}</p> </code>`<code> <p>Use </code>exclusiveMinimum<code>/</code>exclusiveMaximum<code> for strict bounds (in draft-07, these take numeric values).</p> <h3>Array Validation</h3> </code>`<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>`<code> <p>When </code>items<code> is a schema, every element must match it. For tuple validation (different schema per position), set </code>items<code> to an array of schemas.</p> <h3>Object Composition</h3> </code>`<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>`<code> </code>required<code> lists mandatory keys. </code>additionalProperties: false<code> rejects undeclared keys. <h2>Schema Composition</h2> <h3></code>allOf<code>, </code>anyOf<code>, </code>oneOf<code></h3> <ul><li></code>allOf<code> — must be valid against every schema (AND)</li><li></code>anyOf<code> — must be valid against at least one schema (OR)</li><li></code>oneOf<code> — must be valid against exactly one schema</li></ul> </code>`<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>`<code> <p>This is a discriminated union: exactly one branch matches based on the </code>type<code> field.</p> <h3>Reusable Definitions with </code>$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<code>, reference it anywhere with </code>$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<code>) in real time:</p> <strong><a href="https://snappytools.app/json-schema-validator/">JSON Schema Validator — SnappyTools</a></strong> <p>Entirely client-side — your data never leaves the browser. Safe for API payloads with credentials or private configuration.</p> <h2>Validate in Code</h2> <strong>JavaScript (Node.js):</strong> </code>`<code>bash <p>npm install ajv ajv-formats</p> </code>`<code> </code>`<code>js <p>import Ajv from 'ajv';</p> <p>import addFormats from 'ajv-formats';</p> <p>const ajv = new Ajv();</p> <p>addFormats(ajv);</p> <p>const validate = ajv.compile(schema);</p> <p>if (!validate(data)) {</p> <p>console.error(validate.errors);</p> <p>}</p> </code>`<code> <strong>Python:</strong> </code>`<code>bash <p>pip install jsonschema</p> </code>`<code> </code>`<code>python <p>from jsonschema import validate, ValidationError</p> <p>try:</p> <p>validate(instance=data, schema=schema)</p> <p>except ValidationError as e:</p> <p>print(e.message, list(e.absolute_path))</p> </code>`<code> <p>Schemas written for the browser tool work identically in both libraries — same standard, no rewriting.</p> <h2>Common Errors Explained</h2> <strong>"Additional property not allowed"</strong> — your JSON has a field not listed in </code>properties<code>, and the schema has </code>additionalProperties: false<code>. Add the field to the schema or remove it from the JSON. <strong>"Missing required property"</strong> — a field listed in </code>required<code> is absent from the JSON. Either add it or remove it from </code>required<code>. <strong>"Expected type integer, got string"</strong> — the JSON field is a quoted string (</code>"42"<code>) where the schema expects a number (</code>42<code>). Remove the quotes. <strong>"Value must match exactly one schema in oneOf (matched 0)"</strong> — the data doesn't match any branch. Check the discriminator field and the branch conditions. <h2>Summary</h2> <p>| Keyword | Purpose |</p> <p>|---------|---------|</p> <p>| </code>type<code> | Restrict to a JSON type |</p> <p>| </code>properties<code> + </code>required<code> | Define expected object fields |</p> <p>| </code>additionalProperties<code> | Control unknown fields |</p> <p>| </code>enum<code> / </code>const<code> | Restrict to fixed values |</p> <p>| </code>minLength<code> / </code>maxLength<code> | String length bounds |</p> <p>| </code>minimum<code> / </code>maximum<code> | Numeric bounds |</p> <p>| </code>items<code> | Array element schema |</p> <p>| </code>allOf<code> / </code>anyOf<code> / </code>oneOf<code> | Schema composition |</p> <p>| </code>$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/

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Merancang Backend Bisnis ISP: API Pelanggan, Paket Internet, Invoice, dan Tiket Support

Masbadar - Mar 13

5 Web Dev Pitfalls That Are Silently Killing Your Projects (With Real Fixes)

Dharanidharan - Mar 3

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelskiverified - Apr 23

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

Sovereign Intelligence: The Complete 25,000 Word Blueprint (Download)

Pocket Portfolio - Apr 1
chevron_left
2.2k Points86 Badges
93Posts
0Comments
SnappyTools builds free, fast, browser-based tools for developers, writers, and designers. No signup... Show more

Related Jobs

View all jobs →

Commenters (This Week)

1 comment
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!