View all services
Talk to QA Advisor
Free tool · Automation and API

JSON to JSON Schema generator and validator

Paste one or more API responses and get a schema that describes all of them: types, integer or number, nested objects, merged array items, nullable fields and the keys present every time. Then validate any document against it, with every error reported by path and keyword.

JSON Schema generator

Generate a JSON Schema from one or more JSON samples, then validate any document against it. Everything runs in your browser.

Examples
Valid JSON

Add several responses from the same endpoint. Each one teaches the schema which keys are optional and which can be null.

Options

Draft

The current version. Use draft-07 for Postman and older tools.

Required keys

A key is required when every object at that place has it, across all samples and array items.

Becomes the schema title and the file name.

16 properties, 13 required

From 3 samples. 3 formats, 1 nullable, nested 3 levels deep. All 3 samples validate against it.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Order response",
  "type": "object",
  "properties": {
    "orderId": {
      "type": "string"
    },
    "status": {
      "type": "string"
    },
    "total": {
      "type": "number"
    },
    "currency": {
      "type": "string"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "customer": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer"
        },
        "email": {
          "type": "string",
          "format": "email"
        },
        "tier": {
          "type": "string"
        }
      },
      "required": [
        "id",
        "email"
      ]
    },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sku": {
            "type": "string"
          },
          "qty": {
            "type": "integer"
          },
          "price": {
            "type": "number"
          },
          "giftWrap": {
            "type": "boolean"
          }
        },
        "required": [
          "sku",
          "qty",
          "price"
        ]
      }
    },
    "coupon": {
      "type": [
        "string",
        "null"
      ]
    },
    "trackingUrl": {
      "type": "string",
      "format": "uri"
    }
  },
  "required": [
    "orderId",
    "status",
    "total",
    "currency",
    "createdAt",
    "customer",
    "items",
    "coupon"
  ]
}
Export

Indented, ready to save as order-response.schema.json next to your tests.

Use the schema in a test

Save the schema as order-response.schema.json, then assert every response against it.

Paste into the request’s Scripts tab, under Post-response. The schema is embedded as draft-07 because Postman validates with Ajv 6, which does not support 2020-12.

Postman
const schema = {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Order response",
  "type": "object",
  "properties": {
    "orderId": {
      "type": "string"
    },
    "status": {
      "type": "string"
    },
    "total": {
      "type": "number"
    },
    "currency": {
      "type": "string"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "customer": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer"
        },
        "email": {
          "type": "string",
          "format": "email"
        },
        "tier": {
          "type": "string"
        }
      },
      "required": [
        "id",
        "email"
      ]
    },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "sku": {
            "type": "string"
          },
          "qty": {
            "type": "integer"
          },
          "price": {
            "type": "number"
          },
          "giftWrap": {
            "type": "boolean"
          }
        },
        "required": [
          "sku",
          "qty",
          "price"
        ]
      }
    },
    "coupon": {
      "type": [
        "string",
        "null"
      ]
    },
    "trackingUrl": {
      "type": "string",
      "format": "uri"
    }
  },
  "required": [
    "orderId",
    "status",
    "total",
    "currency",
    "createdAt",
    "customer",
    "items",
    "coupon"
  ]
};

pm.test('Response matches the schema', () => {
  pm.response.to.have.jsonSchema(schema);
});
Ready
How to use

How to use the JSON Schema generator

  1. 1Paste a JSON response, or open a file. Add more samples from the same endpoint with Add sample: each one shows which keys are optional and which can be null. The example has three order responses.
  2. 2Choose the draft, which keys are required and whether unknown keys are rejected. Leave format detection on to label dates, emails, URLs, UUIDs and IP addresses.
  3. 3Copy or download the schema, then open Validate JSON to check another response against it, or paste a schema of your own. Each error shows the path, the keyword and the reason.
  4. 4Pick your framework under Use the schema in a test, and copy the code for Postman, REST Assured, Playwright, Jest or pytest.

What a schema generated from samples can and cannot know

A generator sees values, not intent. It can tell that total held a number, that customer was an object with an id and an email, and that every item in the items array had a sku. It cannot tell that total must be positive, that status only ever takes four values, or that an order must contain at least one item. Those rules live in the API specification and the code, not in any one response.

Some types are guesses too. JSON makes no distinction between 1 and 1.0, so a price that happened to be a whole number in every sample is inferred as integer, and the first response with 19.95 in it then fails. Since draft-06 an integer in JSON Schema means any number with a zero fractional part, so the reverse is safe: a field typed number accepts 20. If a field is a decimal by nature, make sure at least one sample shows a fraction, or change integer to number by hand.

Formats are claimed conservatively. A string is only labelled date-time, date, email, uri, uuid or an IP address when every value seen at that place matches the format exactly, and a time must carry its offset, as RFC 3339 requires. A field that held "09:14:02" or "2026-10-26 09:14" stays a plain string.

Required, optional and nullable: why more samples help

With one sample, every key looks required and nothing looks nullable, because the generator has only ever seen each field filled in. Add a second response where coupon is null and the field becomes ["string", "null"]. Add a third without trackingUrl and that key drops out of required. Each extra sample from the same endpoint removes a false constraint.

The same merging happens inside arrays. The items of an array are described by one schema built from every item, so a key that only some items carry is optional, and a value that is a string in one item and null in another is nullable. Use Treat a top-level array as separate samples when you paste a list of whole responses and want the schema of one response, not of the list.

The three required settings answer different questions. In every sample is the honest default: a key is required when every object at that place had it. Every key seen describes a single complete example and will reject your other samples if they differ. None gives a type checker that never complains about a missing field, which suits early exploration but asserts very little.

Draft 2020-12 or draft-07: the differences that matter

For a schema generated from samples, the two drafts produce almost the same document: only the $schema URI changes, plus the uuid format, which draft-07 does not define, so in draft-07 a UUID becomes a pattern. The drafts differ more in what you might add by hand afterwards.

Choose by the tools that will read the schema. Postman’s pm.response.to.have.jsonSchema uses Ajv 6, which supports draft-07 but not 2020-12. REST Assured’s json-schema-validator module supports 2020-12 from version 6.1.0; earlier versions validated with draft-04 rules. Ajv 8 supports both, through a separate class for 2020-12, and Python’s jsonschema supports both.

  • Tuples

    2020-12 uses prefixItems for the positions of a fixed-length array and items for everything after them. Draft-07 used an array form of items with additionalItems.

  • Definitions

    Reusable subschemas live under $defs in 2020-12 and under definitions in draft-07, referenced as #/$defs/name or #/definitions/name.

  • $ref with other keywords

    In draft-07 every keyword beside $ref is ignored. In 2020-12 they apply alongside the reference, so a description or an extra constraint next to $ref takes effect.

  • format

    In 2020-12, format is an annotation by default and a validator only checks it when told to. Draft-07 lets a validator check it. Ajv checks formats once ajv-formats is added; Python’s jsonschema only with a format checker.

  • New keywords

    unevaluatedProperties, dependentRequired and dependentSchemas arrived in 2019-09 and are part of 2020-12. A draft-07 validator ignores them silently.

Tighten a generated schema before it becomes a contract

A generated schema is a first draft of the contract, written from evidence that is necessarily incomplete. Before it guards a test suite, read it against the API documentation and tighten it where the samples could not.

  1. 1

    Check required against the specification

    Remove keys that only looked required because every sample had them, and add ones the specification guarantees. A missing required key is the defect contract tests exist to catch.

  2. 2

    Decide on additionalProperties

    false catches renamed and unexpected fields, which is what a contract test is for. It also fails when the provider adds a field, so use it where the response is meant to be stable, and leave it open on objects designed to grow.

  3. 3

    Add enums and ranges

    status should list its allowed values, quantities need minimum 1, prices exclusiveMinimum 0, and arrays that cannot be empty need minItems 1. Samples rarely show you the edges.

  4. 4

    Pin identifiers and dates

    Add a pattern to identifiers such as ORD-1042, and keep format on dates and emails, then make sure your validator actually checks formats.

  5. 5

    Move repeated shapes into $defs

    When the same object appears in several places, such as an address, define it once and reference it, so a change to the contract is made once.

Schema validation in API tests

Assertions on individual values check what a response says. A schema checks what a response is: every field present, of the right type, with nothing unexpected. One schema assertion catches a price that became a string, a field renamed in a refactor or a null where an object used to be, across every endpoint that returns that shape, without a line of assertion code per field.

Keep the schema next to the tests in version control, validate every response from the endpoint rather than one, and report all errors rather than the first: Ajv needs allErrors: true for that. When a schema assertion fails, decide whether the response or the schema is wrong before changing either, because updating the schema to match a broken response turns a defect into the contract.

Schema validation is not the whole contract test. It cannot say whether a value is correct, only whether it has the right shape, so pair it with assertions on the values that matter. Consumer-driven contract testing, such as with Pact, goes further by checking each consumer’s actual expectations against the provider.

QAble service

API testing

QAble builds API test suites that check schemas, types and contracts on every build, and keeps the schemas in step with the API as it changes.

Explore the service
FAQ

Frequently asked questions

How do I convert JSON to JSON Schema?

Paste the JSON into the generator above, or open a .json file. The schema appears as you type, with a type for every field, nested objects described in full and array items merged into one schema. For a more accurate result, add several responses from the same endpoint as separate samples, so optional and nullable fields are recognised.

Which JSON Schema draft should I use?

Use 2020-12, the current version, unless a tool that reads the schema needs draft-07. Postman’s schema assertion uses Ajv 6, which supports draft-07 but not 2020-12, and REST Assured versions before 6.1.0 do not support either. Ajv 8, Python’s jsonschema and REST Assured 6.1.0 or later support both.

Why is a field missing from required?

With the default setting, a key is required only when every object at that place had it, across all samples and all array items. If one sample or one array item lacked the key, the generator treats it as optional. Check the API specification and add it back if it is guaranteed.

How do I validate JSON against a schema?

Open Validate JSON. The schema box holds the generated schema until you edit it, so you can also paste any schema of your own. Paste the document underneath. Every error is listed with the path in the document, the keyword that failed and the place in the schema, and keywords the validator does not evaluate, such as unevaluatedProperties, are listed rather than silently passed.

Does the validator check format?

Yes, for date-time, date, time, email, uri, uuid, ipv4 and ipv6, the formats the generator detects. Untick Check formats to match a validator that treats format as an annotation, which is the 2020-12 default and the behaviour of Python’s jsonschema without a format checker. Other formats are listed as not checked.

Is my JSON uploaded anywhere?

No. Generation and validation run entirely in your browser and nothing is sent to a server, so it is safe for API responses that contain tokens, personal data or internal identifiers.

Need your API contracts tested?

QAble testers write the schemas, contract tests and negative cases that catch a breaking API change before your consumers do.

Talk to QA Advisor