JSON Schema Generator
Generate a draft 2020-12 schema from a sample, with honest required fields.
Nothing you paste leaves your browser. The connect-src allowlist makes that a browser guarantee rather than a promise. Check it yourself
Generate a JSON Schema from a sample payload. Draft 2020-12 by default, with 2019-09 and draft-07 available.
Generating a schema from one sample is inference, and inference is where these tools quietly lie. Every guess this one makes is reported back to you, and the biggest one is handled differently from most generators.
The required-fields problem
Most generators read the first element of an array and treat its keys as the shape. That produces a schema that rejects valid data the moment a later record has an optional field the first one lacked.
This generator merges every element. A key present in all of them goes into required; a key present in some of them appears in properties but not in required. That single difference is the reason to use a generator rather than write the schema by hand from a glance at the payload.
The other inferences, all reported
- integer against number
- A field is only typed integer when every observed value was one. One decimal anywhere makes the whole field a number.
- Nullable fields
- A field seen as both a string and null becomes "type": ["string", "null"], not a dropped field and not just "string".
- format
- Emitted only when every observed value matches: date-time, date, time, email, uuid, ipv4 or uri. One non-matching value and the annotation is dropped.
- enum
- Suggested rather than assumed, and only when a small set of values repeats. Off by default, because an enum inferred from one sample is a guess about a domain you have not seen all of.
- Unsafe integers
- Typed integer and reported, because a validator running on a JavaScript parser has already lost the value before validation starts.
The format keyword does not validate
This surprises people and ships broken validation. In draft 2019-09 and draft 2020-12, format is an ANNOTATION by default rather than an assertion. Most validators will happily accept "not-an-email" for a field marked "format": "email" unless format assertion is explicitly turned on.
If you need it enforced, add an explicit pattern alongside the format, or configure your validator for assertion behaviour and check that your validator supports it.
A caveat about validating the result
If you take this schema to Ajv, the most common JavaScript validator, mind the entry point. The default ajv export supports draft-07 only. Draft 2020-12 needs ajv/dist/2020 and 2019-09 needs ajv/dist/2019.
Get that wrong and a 2020-12 schema using prefixItems is validated under draft-07 semantics, where prefixItems is an unknown keyword and is ignored. Your validator then reports "valid" on data that is not. That is worse than an error, and it is easy to do by accident.
How to do this in code
Generating and validating in code.
js JavaScript, Ajv
import Ajv from "ajv" gives you a draft-07 validator, which silently ignores 2020-12 keywords.
// The entry point matters. This is the 2020-12 one.
import Ajv2020 from 'ajv/dist/2020';
import addFormats from 'ajv-formats';
const ajv = new Ajv2020({ allErrors: true });
addFormats(ajv); // without this, "format" does nothing at all
const validate = ajv.compile(schema);
if (!validate(data)) console.error(validate.errors); py Python
from jsonschema import Draft202012Validator
validator = Draft202012Validator(schema)
for error in sorted(validator.iter_errors(data), key=lambda e: e.path):
print(list(error.path), error.message)
# Format checking is opt-in here too
from jsonschema import FormatChecker
Draft202012Validator(schema, format_checker=FormatChecker()).validate(data) go Go
import "github.com/santhosh-tekuri/jsonschema/v6"
c := jsonschema.NewCompiler()
sch, err := c.Compile("schema.json")
if err := sch.Validate(data); err != nil {
fmt.Println(err)
} Questions
- Which draft should I use?
- Draft 2020-12 for anything new; it is the current published draft and what OpenAPI 3.1 aligns with. draft-07 remains the most widely supported across older tooling. Note that the identifier 2020-12 refers to when the draft was cut: the documents at that URI were last republished in June 2022, which is a patch rather than a new release.
- Why is a field missing from required?
- Because it was absent from at least one sample. That is the generator telling you something useful. If the field really is mandatory, give it a sample where every record has it, or add it to required by hand.
- Can it generate from several samples?
- Yes, and you should. Put your samples in an array and paste the array. Merging across many records is exactly how required and nullability become accurate.