JSON tools · 6 min read
JSON to JSON Schema: from sample payload to contract
A JSON to JSON Schema conversion takes an example that works and produces a machine-readable description of its shape. That description can validate future payloads, generate documentation, or drive typed code — but only if you treat the generated schema as a first draft. Inference sees one sample, and one sample is a very confident liar.
Updated
What inference can and cannot see
From a single document, a good converter derives types, nesting, array item shapes and property names accurately. What it cannot derive is intent. It does not know that a field is optional because this particular record happened to include it, that a string is an email address, that a number is a positive integer, or that a value comes from a fixed set. Everything derived is therefore marked `required`, which is the right default for a contract draft and the wrong thing to ship unexamined.
Hardening the generated schema
- Compare two or three real samples: keys that are missing from any sample should drop out of `required`.
- Add `format` where the meaning is known — `date-time`, `email`, `uri`, `uuid`, `ipv4`.
- Turn open sets into `enum` values when the field really has a fixed vocabulary, such as a status or region.
- Tighten numbers with `minimum`, `maximum` and `multipleOf` so a negative quantity cannot validate.
- Add `additionalProperties: false` only when unknown keys must be rejected — otherwise leave the schema open for forward compatibility.
Required is a promise, not an observation. Marking a field required because your one sample contained it is the most common way an inferred schema breaks a real integration.
Where the schema earns its keep
The practical value shows up at boundaries: validating a webhook payload before trusting it, checking fixture files in CI so tests fail on malformed data rather than on confusing null errors, documenting an API response for people who will never read the server code, and generating typed clients. A JSON Schema is also the cheapest way to stop a config change from silently altering a public response, because the validator catches it at build time instead of in production.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "email"],
"properties": {
"id": { "type": "string", "format": "uuid" },
"email": { "type": "string", "format": "email" },
"plan": { "type": "string", "enum": ["free", "pro", "team"] }
}
}
Keep it in version control
Generated schemas drift the moment nobody owns them. Commit the hardened file next to the code that produces the data, reference it from the validator in CI, and regenerate only when the contract genuinely changes — treating the schema as the source of truth for the shape and the sample as evidence, not the reverse.
Inference in the browser
Real payloads are full of identifiers, emails and tokens, so a JSON to JSON Schema conversion that uploads the sample is handing over production data for a purely mechanical operation. Inferring locally keeps the payload in the tab, lets you paste a customer record without a second thought, and works with the network cut off.
JSON to JSON Schema — frequently asked questions
Why does every field come out as required?
Because inference sees one sample and that sample contains every field. Required means guarantee, so the generated schema is a starting point: compare a few samples, then remove the keys that are sometimes absent and add `format` or `enum` constraints where you know the real rules.
Which JSON Schema draft should I use?
Draft 2020-12 for new work — it is the current specification and is well supported by validators such as ajv. If you are integrating with a system pinned to draft-07, keep generating draft-07 documents; the two differ mainly in newer keywords you probably will not need.
Can a JSON Schema validate arrays too?
Yes. Array inference produces an `items` schema describing the element shape and a single element shape can be checked with `prefixItems` in modern drafts. Merge two samples with different element shapes and you will see where a `oneOf` is needed.
Tools mentioned in this post
Keep reading
6 min read
JSON to TypeScript: types that match reality
Convert JSON to TypeScript interfaces from a real API response — optional keys, null unions, nested types — and keep generated types from drifting.
6 min read
JSON formatter: pretty, minified, and actually valid
A JSON formatter that pretty-prints, minifies and validates with exact error locations — plus the five syntax mistakes behind almost every invalid JSON error.
6 min read
JSON diff: comparing data the way it is actually structured
Compare two JSON payloads with a structural JSON diff that ignores key order and whitespace, highlights moved values, and shows why text diffs mislead.
- Longer read: JSON to TypeScript: Types That Tell the Truth