JSON Schema Validation: A Practical Guide for API Contracts
"The API changed and broke our integration" is one of the most common, most avoidable failures in software that talks to other software. A field that used to be a string becomes a number. A required field quietly becomes optional. Nobody notices until something downstream throws an exception in production. JSON Schema exists specifically to catch this class of problem before it ships — but most teams who'd benefit from it have never actually set it up, usually because writing a schema by hand looks like a chore.
What JSON Schema actually is
A JSON Schema is itself a JSON document that describes the shape another JSON document is allowed to take: which fields exist, what type each one is, which are required, and constraints like minimum values or string patterns.
{
"type": "object",
"required": ["id", "email"],
"properties": {
"id": { "type": "integer" },
"email": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
}
}
Validate a real payload against that schema, and you get back either "valid," or a precise list of what's wrong — not just a generic parse failure. age: must be >= 0 is a useful error. A stack trace three layers deep in your own code, caused by an unexpected negative number nobody validated, is not.
You don't have to write it by hand
The part that stops most people from bothering: writing a JSON Schema from scratch is tedious, and keeping it in sync with a real, evolving payload by hand is worse. The practical shortcut is to generate the schema from a real sample of the data — grab an actual API response or config file, infer the schema automatically, then adjust it if you want something stricter than what the sample happened to show (turning an inferred "type": "string" into a specific set of allowed values, for instance).
This turns schema-writing from "sit down and think about every field" into "here's a real example, generate the contract, refine it." Much lower activation energy, and the result is grounded in what your data actually looks like rather than what you assumed it looked like.
Where validation actually earns its keep: CI, not just runtime
Runtime validation (checking a payload as your app receives it) is useful, but the higher-leverage place to put JSON Schema validation is earlier — as a CI check that gates a build. If your API's response contract is defined as a schema, you can validate real fixture responses against it on every pull request, and catch a breaking change in a code review instead of in production.
This needs a validator with a real exit code, not just a browser tool — something that fails a CI job when validation fails.
recast validate-schema response.json --schema api-contract.schema.json # exits 1 and prints every violation if it fails — perfect for a CI gate
A minimal workflow
- Grab a real, current sample of the data you want to contract (an API response, a config file).
- Generate a draft schema from it automatically.
- Tighten anything the auto-generated version left too loose — specific enum values, string patterns, explicit min/max.
- Commit the schema alongside the code it describes.
- Validate real fixtures against it in CI, so a contract-breaking change fails the build instead of reaching production.
Recast's JSON Schema Generator infers a draft-07 schema from a real sample in your browser. The Validate Against Schema tool checks a payload against it with the exact violation path and reason for every failure. Both are also available as the recast-cli npm package, with a real exit code, for gating a CI pipeline on schema conformance.