by JSONSchema (LX AI)

Last updated: 2026-10-03

From sample JSON to draft 2020-12 schema

Hand-writing a JSON Schema from scratch is slow, error-prone, and easy to drift away from the payloads your API actually receives. Teams often start with a captured response or a fixture file, then need a strict contract that validators can enforce. This article explains how to move from a concrete sample to a draft 2020-12 schema without pretending that inference alone is a substitute for review.

JSONSchema is built for that workflow: paste sample JSON, emit a draft 2020-12 document, mark required fields with explanations, and surface deterministic checks for missing types, weak formats, and duplicate enum values. The goal is a reviewable contract, not a magic black box that “guarantees compliance.”

Why sample-driven schemas exist

Most API teams already have examples. Postman collections, OpenAPI examples, golden fixtures in CI, and production logs all contain real shapes. Those shapes are more trustworthy than a blank editor, yet they are still incomplete. A sample shows presence, not absence. It shows one type, not every legal type. It rarely shows nullability, empty arrays, or deeply nested optional branches.

Inference tools encode that incomplete picture into a starting schema. Used well, they save hours of boilerplate. Used poorly, they freeze accidents into policy: a typo becomes a required property, a number that happened to be an integer becomes forever non-float, and an extra debug field becomes part of the public contract.

The right mental model is scaffolding. You generate a candidate, then you tighten, loosen, and document until the schema matches product intent. Draft 2020-12 gives you the vocabulary for that tightening: required, additionalProperties, unevaluatedProperties, $defs, $ref, and format annotations that validators may or may not enforce.

What draft 2020-12 means in practice

JSON Schema has evolved through several dialects. Draft 2020-12 is the dialect most modern tooling expects when you want consistent core vocabulary. It separates the core specification from validation and from the format vocabulary. That separation matters because “format” is advisory unless a validator is configured to assert formats.

In 2020-12, reusable definitions live under $defs rather than the older definitions keyword. Dynamic references and the evaluation model for applicator keywords are clearer than in earlier drafts. If you still maintain draft-07 schemas for legacy services, do not mix dialects inside one document without a deliberate migration plan.

For product work, pinning $schema to the 2020-12 meta-schema URL is more than decoration. It tells reviewers and validators which keyword set you claim to use. JSONSchema emits that dialect so downstream AJV setups and CI gates share one expectation.

How inference typically walks a sample

A practical inference pass walks the JSON tree and assigns a type keyword to each node. Objects become type: object with a properties map. Arrays become type: array with an items schema derived from element samples. Scalars become string, number, integer, boolean, or null when the sample literally contains null.

Strings that look like emails or URIs may receive a format annotation. That annotation is a hint, not a cryptographic guarantee that every future value will be valid according to the format vocabulary. Numbers that look whole may be typed as integer; that choice is convenient for IDs but wrong for money amounts that sometimes arrive as decimals.

Keys present on the sample object are often added to required. That is useful when the sample represents a mandatory response body. It is harmful when the sample is a “full” fixture that includes optional marketing fields. Reviewers must decide which keys are truly required for clients and which are optional enrichment.

Required fields: the first place inference lies

Marking every observed key as required is the most common sample-to-schema pitfall. Consider a user profile payload that includes avatarUrl because a designer populated the fixture. If inference locks avatarUrl into required, clients that omit avatars will fail validation even though product rules allow it.

The opposite mistake is equally dangerous. If your sample omits a field that is mandatory in production, inference will treat it as optional. Checkout payloads that sometimes omit currency in local fixtures are a classic case. The schema then green-lights incomplete orders until a human reintroduces the requirement.

A workable review checklist asks three questions for each property: Must this key always appear for this operation? May it be null when present? Does absence mean something different from an empty string? JSONSchema surfaces automatic required marks with plain-language explanations so that checklist stays visible during review instead of buried in a diff of braces.

Types, formats, and enum hygiene

Type inference from one value cannot express unions. A field that is sometimes a string ID and sometimes a nested object will look like whichever shape the sample chose. If your API accepts either, you need oneOf or anyOf written by a human after inference.

Format keywords such as email, uri, uuid, and date-time improve documentation and enable strict validators. They also create false confidence. Not every email-looking string is RFC-compliant, and not every URI validator agrees on what “uri” means. Prefer asserting formats in CI only after you confirm your AJV (or equivalent) configuration treats formats as errors rather than warnings.

Enums inferred from a single sample often contain one value. That is almost never what you want. Duplicate enum entries are a separate defect: they confuse generated clients and signal that someone merged lists carelessly. Deterministic rules that flag missing types, weak formats, and duplicate enums catch these before the schema ships.

{
  "$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" },
    "role": { "type": "string", "enum": ["admin", "member", "viewer"] }
  },
  "additionalProperties": false
}

The example above is intentional, not inferred. Notice the closed object via additionalProperties: false, the explicit required list, and an enum with distinct values. Sample inference might have produced a looser variant; the review step closes the gaps.

additionalProperties and the closed-object decision

Open objects accept unknown keys. Closed objects reject them. Inference rarely knows which policy you want. Public request bodies often benefit from closed objects so typos like emial fail loudly. Event streams that forward vendor extensions sometimes need open objects or a defined extension bag.

Setting additionalProperties: false after inference is a deliberate product choice. Leaving the default (unconstrained additional properties in many tools) means clients can smuggle fields you never reviewed. In draft 2020-12, also learn when unevaluatedProperties is the right applicator, especially once you compose schemas with allOf.

JSONSchema’s compliance ruleset flags patterns that leave contracts too loose for typical API gateways. That does not replace your gateway configuration; it reduces the chance that the schema document itself silently invites surprise keys.

$ref, $defs, and composition pitfalls

Large schemas need reuse. Moving repeated address blocks into $defs and pointing with $ref keeps documents maintainable. Sample inference usually emits a flat tree first. Flattening is fine for small payloads; it becomes unreadable once the same nested shape appears in request and response.

Common $ref mistakes include pointing at the wrong fragment, mixing relative URI resolution with incorrect base documents, and assuming every OpenAPI $ref behaves identically to JSON Schema core. OpenAPI Schema Objects are related but not identical to pure JSON Schema dialects. If you export for both worlds, validate in both toolchains.

Circular references, mutual recursion, and over-aggressive inlining can break some generators. Prefer shallow, named definitions for shared value objects. Avoid inventing refs that your sample never justified—refactor after the inferred tree is correct.

OpenAPI versus JSON Schema (do not conflate them)

OpenAPI 3.x uses a Schema Object that historically diverged from JSON Schema and has been converging carefully. Keywords, nullable modeling, and discriminator usage differ across OpenAPI versions. A valid draft 2020-12 document is not automatically a drop-in OpenAPI component without checking your OpenAPI version and tooling.

Teams often paste a JSON Schema into components/schemas and assume Swagger UI will honor every keyword. Some keywords are ignored; some are rejected. Treat OpenAPI as a publishing and documentation layer, and keep a dialect-correct JSON Schema for runtime validation when you need strict draft 2020-12 behavior.

JSONSchema focuses on the schema document and plain-language validation explanations. It is not an OpenAPI editor, not a mock server, and not a substitute for your gateway’s request validation plugin.

Validator realities: AJV and friends

AJV is a common choice for Node services validating draft 2019-09 and 2020-12. Configuration details change outcomes: whether formats are asserted, whether unknown formats warn or fail, and how strict mode treats unsupported keywords. A schema that “works in the playground” can still fail in CI if versions differ.

Other ecosystems use different validators with different dialect support matrices. Always record the validator name and version next to the schema dialect. When JSONSchema exports a report with a runId, that identifier helps you correlate a generated candidate with a later CI failure instead of debating which pastebin someone used.

Fail closed when AI assistance is unavailable. If live model assistance cannot run, the product should return a clear not-configured or upstream-failed state rather than inventing a schema under HTTP 200. Deterministic rule checks remain available; they must be labeled as rule-based when they are not model-assisted.

Catalog of sample-JSON to schema pitfalls

  1. Single-sample tunnel vision: one fixture cannot reveal optional keys or alternate branches.
  2. Integer coercion: whole numbers become integer forever, breaking decimal money and rates.
  3. Null blindness: missing null in the sample hides nullable fields.
  4. Empty array silence: empty arrays give no item schema; nonempty arrays overfit to one element shape.
  5. Date strings as plain strings: without format review, ISO timestamps remain untyped text.
  6. Enum from one literal: a single observed status becomes a one-value enum.
  7. Duplicate enum values: merged lists create redundant entries that confuse codegen.
  8. Required inflation: optional fixture fluff becomes mandatory.
  9. Required deflation: incomplete fixtures omit keys that production demands.
  10. Open object drift: unconstrained additional properties invite typo fields into production.
  11. Nested map confusion: objects used as dictionaries need additionalProperties schemas, not infinite property lists.
  12. Binary and base64: string content encodings need explicit intent, not guesswork.
  13. Locale and currency: ISO codes deserve enums or pattern constraints after product review.
  14. Ref premature optimization: extracting $defs before the flat tree is correct multiplies errors.
  15. Dialect mismatch: copying draft-07 examples into a 2020-12 document without keyword migration.

Each pitfall has the same remedy: treat inference as a draft, then apply a human checklist aligned with API product rules. Deterministic scanners help, but they cannot invent missing product knowledge.

A practical generation and review workflow

Start with a representative sample that matches the operation you care about—create order request, not a mixed bag of unrelated keys. Generate a draft 2020-12 schema. Inspect required fields and remove optionals that slipped in. Decide open versus closed objects. Add formats only where your validators will enforce them. Collapse repeated structures into $defs after the flat version is correct.

Export the candidate with a stable runId so engineering chat, tickets, and CI logs can point at the same artifact. Attach plain-language validation rules beside the schema so reviewers who do not live in JSON Schema keywords can still approve reject behavior. Re-run against fixtures that include nulls, empty arrays, and edge statuses before you merge.

Price and packaging honesty matters for tools in this space. JSONSchema sells workflow runs for schema generation and review assistance—not “unlimited AI credits” theater and not a legal certification. Listed plans are published on the product pricing page; assistants must not invent discounts or enterprise features that are not shipped.

What it is not

JSONSchema is not a law firm, auditor, or certification body. Generating a schema does not prove GDPR compliance, PCI compliance, accessibility conformance, or contractual fitness. It does not replace penetration testing or a security review of your API surface.

It is not a guarantee that every future payload will be valid, that every validator will behave identically, or that inferred formats will catch every bad email or URI. It does not silently mock live AI results when the model is unavailable. It does not claim 100% coverage, never-miss detection, or automatic OpenAPI parity.

Use the output as decision support for developers who still own the contract. If you need a human for billing or product questions, contact support with your runId and account email rather than asking the in-app assistant to change subscriptions.

Checklist before you merge the schema

Frequently asked questions

Which dialect should new services pick?

Prefer draft 2020-12 for new contracts unless a hard dependency forces an older dialect. Migration later costs more than pinning early.

Can one sample ever be enough?

Only for tiny, stable value objects—and even then you should still add negative fixtures. Anything with optionality needs more than one example.

Does JSONSchema mark required fields automatically?

Yes. It marks required fields from the sample and explains why, so you can demote optionals before shipping.

References

Want to try the product? JSONSchema

Updated 2026-09-26 · primary sources only · no fabricated traffic metrics

FAQ

Which JSON Schema dialect does sample inference target?

JSONSchema targets draft 2020-12 so that modern validators such as AJV can enforce a shared contract.

Why is one sample insufficient for a production schema?

A single payload never shows optional keys, alternate types, or empty arrays, so inference must be reviewed before shipping.