Skip to content
JSONCraft

Schema & Validation

JSON Schema: validate a small subscription contract

Try a complete 2020-12 schema with valid and invalid inputs, conditional requirements and an explicit policy for extra fields.

A useful schema describes an actual contract and comes with examples it should accept and reject. It does not replace authentication, authorization or resource limits before parsing.

Try the complete example

Open the JSON Schema validator. Put this schema in the schema panel; the same file is available as subscription.schema.json.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "plan",
    "seats"
  ],
  "properties": {
    "plan": {
      "enum": [
        "basic",
        "pro"
      ]
    },
    "seats": {
      "type": "integer",
      "minimum": 1,
      "maximum": 25
    },
    "company": {
      "type": "string",
      "minLength": 1
    }
  },
  "if": {
    "properties": {
      "plan": {
        "const": "pro"
      }
    },
    "required": [
      "plan"
    ]
  },
  "then": {
    "required": [
      "company"
    ]
  }
}

This fictional subscription has two plans. seats must be an integer between 1 and 25. A pro plan also needs a non-empty company name. Those bounds describe this example, not a recommended commercial plan.

Try these inputs separately:

Scroll horizontally to see all columns.

Input Expected result and reason
{"plan":"basic","seats":2} Valid
{"plan":"pro","seats":3,"company":"Example"} Valid
{"plan":"pro","seats":3} Invalid: missing company
{"plan":"basic","seats":0} Invalid: seats below the minimum
{"plan":"basic","seats":"2"} Invalid: string instead of integer
{"plan":"basic","seats":2,"admin":true} Invalid: an extra field

For these test cases, verify the error identifies the relevant input or schema path. Do not fix a rejected input by silently coercing types unless the receiving application explicitly defines that behavior.

Required, additional and conditional fields

properties describes values when present; required demands presence. An empty company name fails minLength; merely including the key is not enough. The conditional branch adds a requirement for pro without duplicating the whole schema.

Rejecting extra properties is appropriate for this closed contract. Some extension or metadata objects intentionally allow arbitrary keys. Choose that policy explicitly at each object level. When using composition, additionalProperties only knows the properties declared alongside it; newer drafts also provide unevaluatedProperties for composed schemas.

Choose a dialect your validator supports

The $schema URI identifies the intended dialect. JSONCraft uses @cfworker/json-schema with 2020-12 as the default, and your backend may use a different validator or dialect. Check support before copying newer keywords into a Draft 7 environment. In particular, 2020-12 uses prefixItems for tuple positions; do not mix it with older array-form items examples.

Local references can reuse definitions through $defs. Resolve approved schemas under application control; accepting arbitrary network references adds a separate availability and security problem.

Formats and validation limits

Whether format asserts validity depends on the dialect, vocabulary and validator configuration. Test the exact implementation. An email-shaped string does not prove a mailbox exists, and a URL-shaped string does not establish that fetching it is safe. Keep domain-specific checks separate.

Limit request size and computational work before invoking a validator. A schema checked after parsing cannot prevent every parser allocation. See input security and use the formatter to distinguish syntax errors from contract errors.

References: JSON Schema objects, conditional validation, formats, and the validator used by JSONCraft.

Related tools

Frequently asked questions

Does properties make a field mandatory?

No. Use required for presence, then constrain the value with properties. A present null is different from a missing field.

Does additionalProperties: false apply to every nested object?

No. It applies to the object schema containing it. Define nested contracts deliberately and take care when composing schemas.

By