by JSONSchema (LX AI)

Last updated: 2026-10-03

Plain-language validation rules for APIs

A JSON Schema can be correct and still fail a pull request review. Reviewers skim nested keywords, miss which properties are required, and argue about whether an unknown field should be rejected. Plain-language validation rules sit beside the schema so engineers, PMs, and support leads share one reject story.

JSONSchema turns sample JSON into a draft 2020-12 schema and pairs it with human-readable checks: missing types, bad formats, duplicate enums, and required-field explanations. This article focuses on writing those rules so they stay honest, testable, and useful in CI—without claiming to be a security audit or a legal certification.

The review problem schemas alone do not solve

Schema documents optimize for machines. Humans optimize for sentences. When a PR only contains a thousand-line schema diff, reviewers ask the wrong questions: “Does AJV support this keyword?” instead of “Should we reject orders without currency?” The business rule gets lost inside applicator keywords.

Plain-language rules restate the contract as decisions. Each rule names the input condition, the expected reject or accept outcome, and the schema keyword that encodes it. That mapping lets a reviewer challenge the product decision without needing to parse unevaluatedProperties on the spot.

Good rules are short, specific, and falsifiable. Bad rules are slogans—“validate everything,” “never trust the client”—that cannot be turned into a failing unit test. Prefer “Reject create-order when currency is missing” over “Ensure completeness.”

Anatomy of a useful plain-language rule

Every useful rule has four parts: scope, condition, action, and evidence. Scope names the operation or payload (for example, POST /v1/orders). Condition describes the bad or good input. Action states accept or reject (and preferably the HTTP status your API returns). Evidence points at the schema fragment or fixture that proves the rule.

Example rule: For POST /v1/orders, reject the request when the body omits currency. Encode with required including currency. Fixture: order-missing-currency.json must fail validation.

Notice the rule does not claim the API is PCI certified. It does not promise that every validator worldwide will behave identically. It states one reject behavior your team agrees to enforce.

When JSONSchema auto-marks required fields, convert each mark into a rule like the example. If a field was only present because the sample was chatty, demote it from required and delete the corresponding rule before merge.

Mapping draft 2020-12 keywords to sentences

Type keywords become sentences about kinds of values. “email must be a string” is weaker than “email must be a string matching format email when format assertion is enabled.” The second sentence admits that format behavior depends on validator configuration—an honesty detail many teams skip.

Required arrays become “must include.” Enums become “must be one of.” Const becomes “must equal.” minimum and maximum become numeric bounds with units when possible (“amount must be at least 0 in the minor currency unit”). Pattern becomes a prose description plus the regex, never the regex alone.

additionalProperties: false becomes “reject unknown keys at this object.” That sentence forces a product conversation about extension fields. If marketing wants to attach experimental flags, either open the object, add an extensions map, or document a versioned escape hatch. Silent openness is how typos become data.

Reject unknown top-level keys on POST /v1/orders.
Schema: additionalProperties false on the root object.
Fixture: order-with-typo-emial.json must fail.

Composition keywords need careful prose. allOf means every branch applies. anyOf means at least one branch applies. oneOf means exactly one branch applies. Writing “must match the payment shape” is ambiguous; writing “must match exactly one of cardPayment or walletPayment” matches oneOf intent.

Required fields without theater

Required-field rules are where sample inference most often overreaches. Translate each required entry into a customer-visible consequence. If omitting avatarUrl does not break account creation, it should not be required, and no rule should claim otherwise.

Also distinguish missing keys from null values. Some APIs treat null as “clear the field” while absence means “leave unchanged.” Schema and prose must agree. A rule that says “reject null email” is different from “reject missing email.” Write both if both matter.

Batch endpoints complicate required lists: an item inside an array may require fields that the envelope does not. State the scope explicitly—“each element of items[] must include sku”—so reviewers do not apply root required rules to nested objects.

Formats, emails, URIs, and false confidence

Format annotations look like guarantees. They are not. In draft 2020-12, format is a vocabulary that validators may assert or ignore. Your plain-language rule must say whether your deployment asserts formats. Otherwise QA will file bugs when a playground accepts a loose email that production rejects—or the reverse.

Email and URI formats vary across libraries. Prefer rules that name the validator: “AJV with formats enabled rejects email values that fail the configured email format.” Pair that with fixtures that include edge cases you care about, not every RFC curiosity.

UUID and date-time formats are easier to agree on, yet still deserve fixtures. A date-time without timezone may pass one library and fail another. Document the expected profile in prose so on-call engineers are not guessing at 2 a.m.

Enum duplicates and status vocabularies

Status fields are classic enum territory. Plain-language rules should list allowed values and the product meaning of each. Duplicate enum entries are defects: they confuse generated clients and suggest a merge error. Deterministic checks that flag duplicate enums turn that defect into a blocking CI signal.

When a sample contains only "pending", inference may create a one-value enum. The matching plain-language rule would falsely claim the API only ever accepts pending. Expand the enum to the real lifecycle, or remove the enum until product confirms the vocabulary.

Avoid encoding temporary feature flags as permanent enums. If a status is experimental, say so in the rule and keep the schema in a feature branch until the vocabulary stabilizes.

Reject stories for arrays and empty collections

Empty arrays hide item schemas. A rule that only says “items must be an array” accepts empty lists even when business logic requires at least one line item. Add minItems prose when product demands it: “orders must include at least one line item.”

Heterogeneous arrays need explicit stories. If items can be product or discount lines, say so and point at oneOf. If someone pastes a sample with only products, inference will under-specify discounts. Plain language makes the missing branch visible before production traffic invents it.

Tuple-like arrays (fixed positions) are rare in JSON APIs but appear in legacy payloads. Prefer named objects over positional arrays when you can. When you cannot, write rules that name positions (“index 0 is latitude”) so maintainers do not reverse coordinates by accident.

AJV, CI gates, and fail-closed AI assistance

Plain-language rules should name the validator that enforces them. “Should reject” without a CI hook is documentation theater. Wire fixtures to AJV (or your stack’s validator) and fail the build when a fixture that ought to fail actually passes.

Keep dialect and validator versions in the same checklist as the rules. Draft 2020-12 in the schema plus an older validator in CI is a common source of “works on my machine” debates. Record both next to the export runId from JSONSchema so artifacts stay correlatable.

When model assistance is used to draft rules or schemas, fail closed if the model is unavailable. Return a clear not-configured or upstream-failed response instead of inventing rules under a successful HTTP status. Rule-based scanners may still run; label them rule-based so nobody mistakes them for live model output.

OpenAPI docs versus runtime validation rules

OpenAPI shines at describing operations for humans and generated clients. Runtime validation often uses a JSON Schema dialect directly inside the service. Plain-language rules should say which layer enforces which reject. “Documented in OpenAPI” is not the same as “enforced in the request pipeline.”

Schema Objects in OpenAPI may ignore or reinterpret some JSON Schema keywords depending on version. If your public docs show a looser contract than your runtime, support tickets will multiply. Align the prose: either loosen runtime, tighten docs, or explicitly document intentional differences.

JSONSchema helps you produce the schema and the explainers; it is not a full OpenAPI authoring suite. Export, then verify in both the OpenAPI linter you use and the runtime validator.

Sample-JSON pitfalls that break plain-language rules

  1. Rules copied from an over-complete fixture invent false requirements.
  2. Rules copied from an under-complete fixture omit real requirements.
  3. Integer inference creates numeric rules that reject legitimate decimals.
  4. Missing null samples omit null-handling rules entirely.
  5. One-value enums publish incomplete status vocabularies.
  6. Open objects leave no rule for unknown keys, so typos slip through.
  7. Format rules claim enforcement the validator never enables.
  8. $ref refactors move keywords while stale prose still points at old paths.
  9. OpenAPI-only reviews approve docs that runtime never enforces.
  10. Duplicate enum values create contradictory “allowed list” sentences.

Each pitfall is prevented by pairing every rule with a fixture and by re-reading rules after any schema refactor. Treat runId-tagged exports as the source for both artifacts so prose and schema cannot silently diverge across chat threads.

Writing rules non-specialists can challenge

Support and success teams often spot contract bugs first. Give them rules that avoid jargon where possible, and define jargon when unavoidable. “Reject additional properties” can be rewritten as “Reject fields we did not document for this request.”

Keep an honesty banner near commercial claims. Pricing for JSONSchema is published as workflow runs (listed plans such as monthly and yearly on the pricing page). Do not let marketing copy imply that buying a plan certifies your API for any regulation.

When the in-app assistant answers questions about rules, it should retrieve product knowledge rather than invent integrations. If a human is needed for billing or account changes, direct people to lixingliangsy@163.com with the relevant runId.

What it is not

Plain-language validation rules are not a security audit, penetration test, or threat model. They do not prove that authorization checks exist, that rate limits are correct, or that injection defenses are adequate. Schema validation is necessary for contract integrity; it is not sufficient for application security.

They are not a legal certification, accessibility attestation, or compliance seal. Shipping a schema with clear reject rules does not mean you meet GDPR, SOC 2, or industry mandates. Do not use words like guarantee, 100%, or never miss when describing detection of invalid payloads.

They are also not a substitute for owning the product decision. Tools can draft candidate rules from samples; humans still decide whether unknown keys fail, whether currency is mandatory, and whether format assertions are on. JSONSchema will not pretend a demo answer is live AI when the model path is down.

A lightweight operating cadence

On each contract-changing PR, update the schema, update the plain-language list, and update fixtures in the same commit. Reviewers should be able to read the rule list first and only dive into keywords when they disagree. Once a week, spot-check that CI still runs format assertions the way the rules claim.

When you regenerate from a new sample, diff the rule list, not only the schema. Regeneration that silently adds required fields will show up as new reject sentences—easier to catch than a one-line change inside a nested properties map.

Archive exports with runIds next to release notes for APIs that external partners consume. Partners ask “what changed?”; pointing at a dated rule list answers faster than asking them to diff raw JSON Schema.

Frequently asked questions

Do plain-language rules replace the schema?

No. Machines still need the schema. Humans need the sentences. Keep both, linked by fixtures and a shared runId.

Should every keyword become a rule?

No. Prioritize required fields, closed-object policy, enums, formats you assert, and composition branches that change money or identity flows.

Is this a security product?

No. It helps teams express and review API validation intent. Pair it with proper security practice elsewhere.

References

Want to try the product? JSONSchema

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

FAQ

Why translate JSON Schema into plain-language rules?

Most reviewers approve reject behavior faster when rules read like product statements instead of nested keywords.

Are plain-language rules a security audit?

No. They describe validation intent for API contracts and do not replace threat modeling or penetration tests.