Stop hand-writing JSON Schemas: infer them from your sample payloads, in the browser
Hand-writing a JSON Schema from an API response is tedious, error-prone work. The more fields a payload has, the easier it is to forget a required entry or mistype a field. And the schema you write by hand is only as goo
Hand-writing a JSON Schema from an API response is tedious, error-prone work. The more fields a payload has, the easier it is to forget a required entry or mistype a field. And the schema you write by hand is only as good as the sample you stared at while writing it.
There is a faster first draft: paste sample payloads into an inference tool and let it generate the schema. I tried ToolsByUs's JSON Schema Generator — it infers a Draft 2020-12 schema from your samples and validates documents against it on the spot, all in the browser. Your sample data never leaves the tab, because the whole thing runs client-side.
The sample I ran through it
[
{"id": 1, "name": "taro", "email": "[email protected]", "status": "active", "created_at": "2026-11-01T09:00:00Z"},
{"id": 2, "name": "hana", "email": "[email protected]", "status": "inactive", "created_at": "2026-11-02T10:30:00Z", "nickname": "h"}
]
What the inference actually gets right — and one thing it doesn't
-
required detection: only properties present in every sample become required. Here
id,name,email,statusandcreated_atare required;nicknameappears in only one of the two samples, so it stays optional. That is exactly the rule you would apply by hand, applied without fail. -
format detection:
emailis inferred asformat: emailandcreated_atasformat: date-time. UUIDs and URIs are detected the same way. -
The enum surprise: strings with few distinct values can become enums — but not always. The default threshold is 4, yet when I ran this sample,
statusstayed a plain{"type": "string"}despite having only two values,activeandinactive. No enum was generated. So a small value set does not guarantee an enum; check the output rather than assuming. -
Type widening: when the same key holds an integer in one sample and a string in another, the inferred type widens to
["integer", "string"]instead of silently picking one.
Validate without leaving the page
The round-trip validator below the generator takes a test payload and checks it against the generated schema in real time, showing which path and keyword failed on a violation. That kills the usual loop of writing a schema, opening a second tool to validate it, going back to fix it, and re-validating. One page does both halves.
Honest caveats
- Inference only sees the samples you give it. A field that happens to be present in every sample is treated as required even if it is optional in reality. If a field is optional, include a sample where it is missing and it drops out of
required. - The inferred schema is a starting point, not a finished contract. Read it before shipping it — especially the
requiredlist and anyformatit guessed. - If all you need is TypeScript types, the same site's JSON-to-TypeScript converter is the better tool. A schema is the artefact you want when several languages need runtime validation against the same contract.
- Client-side means your machine does the work and your data stays local. For very large payloads that can be slower than a server — but for the hand-sized samples you actually infer schemas from, it is instant.
If you have API samples lying around, the first draft of your schema takes seconds. Spend the saved time on the part that matters: checking whether the inferred schema matches what your API actually promises.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.