The OpenAPI Initiative publishes a JSON Schema for each version of the spec: one for Swagger 2.0, and one each for OpenAPI 3.0, 3.1, and 3.2. Validating a document means checking it against the schema for the version it declares. That catches most of the mistakes that make codegen tools choke or documentation render wrong. It doesn't catch all of them, because some rules compare one part of the document with another, and a JSON Schema can't express that. The validator on this site runs both kinds of check, and this guide covers what each one finds.
Mistakes the schema catches
These are the ones that come up again and again, usually in specs written by hand or edited without a linter:
- A response without a
description. It's required on every response object in both 2.0 and 3.x, even when there's nothing interesting to say.'204': {}is invalid;'204': { description: No content }is fine. - A path parameter without
required: true. A parameter that appears in the URL template can't be optional, so the spec makes you say so explicitly. in: bodyin a 3.0 file. That's a Swagger 2.0 habit. In 3.x, request bodies moved torequestBody, andinonly acceptspath,query,header, orcookie.- A type array in a 3.0 schema.
type: [string, "null"]is valid in 3.1, which adopted JSON Schema 2020-12. In 3.0,typeis a single string and nullability isnullable: true. Specs upgraded halfway hit this one a lot. - A typo in a type, like
type: strngin a 3.0 schema. - Fields the spec doesn't define. Most OpenAPI objects reject unknown keys, so a leftover
definitionsblock at the top of a 3.0 file is an error. Custom fields are allowed, but their names have to start withx-. The same rule catches a path written aspetsinstead of/pets.
One mistake, one message
The official schemas describe a lot of places as "either a $ref or the real object", and parameters as "one of path, query, header, or cookie". A standard validator reports a failure for every alternative that didn't match. So a single missing description comes back as three errors, and a parameter with in: body comes back as eight, most of them about alternatives you never meant to use. This tool works out which alternative you were writing and reports only its problem. For the in: body case that's one line saying in must be one of path, query, header, or cookie. Locations are written the way you'd reach them in code, like paths["/pets/{id}"].get.parameters[0], so you can find the spot without decoding a JSON pointer.
What a JSON Schema can't check
A schema describes what each part of a document is allowed to look like, one part at a time. Some rules are about how parts relate to each other, so the validator checks them separately:
- Every internal
$refresolves.#/components/schemas/Useris a perfectly well-formed string whether or not aUserschema exists. The validator walks the path through the document to make sure it does. References to other files or URLs are skipped, since a single pasted document has nothing to resolve them against, and flagging a valid external reference would be worse than not checking it. - No two operations share an
operationId. The spec requires them to be unique. Code generators use them as function names, so a duplicate usually means one endpoint silently overwrites another in the generated client. - Every path declares at least one operation. This is a warning rather than an error. A path with no methods is legal but almost always a leftover.
One gap to know about in 3.1 and 3.2
In 3.1, Schema Objects became full JSON Schema 2020-12, and the official 3.1 and 3.2 schemas check only that each one is an object or a boolean. They leave the contents to a separate "dialect" schema. So a type: strng inside components.schemas is caught in a 3.0 document but not in a 3.1 one. Everything outside Schema Objects, including paths, operations, parameters, and responses, is checked fully in every version.
The version field, and a YAML trap
The validator picks the schema from the openapi or swagger field, so it has to be exact. openapi needs a patch number (3.1.0, not 3.1). In YAML, write it in quotes. openapi: 3.0 without quotes is read as the number 3, which isn't a version at all, and every tool downstream will reject it for a reason that's hard to spot.
What a valid spec doesn't tell you
Passing validation means the document is a well-formed OpenAPI description. It doesn't mean it describes the API you actually run. A spec can be perfectly valid and still say a field is a string when the server sends a number. Catching that takes real responses, which is what API contract testing is about.
Everything runs in your browser. The YAML parser and the schema for your document's version download the first time you validate, and nothing you paste is sent anywhere.