YamlBox

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

  1. Compare two or three real samples: keys that are missing from any sample should drop out of `required`.
  2. Add `format` where the meaning is known — `date-time`, `email`, `uri`, `uuid`, `ipv4`.
  3. Turn open sets into `enum` values when the field really has a fixed vocabulary, such as a status or region.
  4. Tighten numbers with `minimum`, `maximum` and `multipleOf` so a negative quantity cannot validate.
  5. 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

Browse all 19 tools →

Keep reading

All 19 posts →