OpenAPI 3.x vs Swagger 2.0: What Changed and How to Validate a Spec
July 26, 2026 · DevTools
You inherit an API. The documentation is a wiki page from 2018 that links to a swagger.json file in the repo. You open the file, recognise every field, and try to generate a client SDK with the modern tooling — which promptly errors out because the file is Swagger 2.0 and the generator only accepts OpenAPI 3.x. The question you ask first is the right one: what actually changed?
You can try every example in this guide with the OpenAPI / Swagger Editor. Paste a spec — JSON or YAML, 2.0 or 3.x — and the tool parses it, checks that the required blocks are present, lists every operation, and re-emits a formatted JSON copy. Parsing is entirely client-side; nothing leaves your browser.
A quick bit of history
The format's history explains why both names still appear:
- Swagger 1.x / 2.0 — created by SmartBear in 2011 and donated to the OpenAPI Initiative in 2015
- OpenAPI 3.0 — the first release under the Linux Foundation stewardship, in 2017
- OpenAPI 3.1 — released in 2021, harmonised with JSON Schema 2020-12
- OpenAPI 3.2 — released in 2024, adds webhooks, streaming, and a few other long-requested features
In everyday speech, "Swagger" is still common even when the format is OpenAPI. The editor tools ("Swagger Editor", "Swagger UI", "Swagger Codegen") keep the original name; the file format is now OpenAPI. The two terms are mostly interchangeable today, except when you're talking about Swagger 2.0 specifically, which is the last format with the "Swagger" name.
The shape: what stayed the same
Both formats describe the same thing — an HTTP API — in roughly the same shape:
openapi: 3.1.0 # Swagger 2.0 says "swagger: 2.0"
info: # title + version + description (identical structure)
title: Pet Store
version: 1.0.0
servers: # Swagger 2.0 uses "host", "basePath", "schemes" instead
- url: https://api.example.com/v1
paths: # same shape: /pets, /pets/{id}, etc.
/pets:
get: # operation: method + summary + parameters + responses
summary: List pets
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
components: # Swagger 2.0 uses "definitions" and "parameters" at the top level
schemas:
Pet:
type: object
properties:
id: { type: integer }
name: { type: string }
If you've written one, you can read the other. The differences are concentrated in a few specific places.
What actually changed
1. The version field
| Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 |
|---|---|---|
swagger: "2.0" | openapi: 3.0.0 | openapi: 3.1.0 |
The version string is the simplest discriminator. If your file starts with swagger: "2.0", it's Swagger. If it starts with openapi:, it's OpenAPI 3.x.
2. Servers vs host + basePath + schemes
Swagger 2.0 had three separate fields — host, basePath, schemes — that combined to describe where the API lived:
# Swagger 2.0
swagger: "2.0"
host: api.example.com
basePath: /v1
schemes:
- https
OpenAPI 3.x replaces all three with a single servers array, and adds templated variables:
# OpenAPI 3.x
openapi: 3.0.0
servers:
- url: https://api.example.com/v1
- url: https://{environment}.example.com/v1
variables:
environment:
default: api
enum: [api, staging]
If you're converting a 2.0 spec to 3.x, merge host, basePath, and schemes into one URL string and put it in servers.
3. definitions → components/schemas
Swagger 2.0 had definitions as a top-level key for reusable schemas. OpenAPI 3.x moves them under components/schemas:
# Swagger 2.0
definitions:
Pet:
type: object
# OpenAPI 3.x
components:
schemas:
Pet:
type: object
The same applies to parameters and responses: both moved under components/.
4. Request bodies: separate from parameters
Swagger 2.0 used a single parameters array, with in: body distinguishing body fields from query and header fields. OpenAPI 3.x splits them:
# Swagger 2.0 — body mixed with parameters
paths:
/pets:
post:
parameters:
- name: pet
in: body
schema:
$ref: "#/definitions/Pet"
# OpenAPI 3.x — requestBody is separate
paths:
/pets:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
This is the single biggest source of converter errors. A Swagger-to-OpenAPI tool has to scan every parameters array and lift anything with in: body into a requestBody.
5. Form parameters split
Form parameters (in: formData) became first-class requestBody content with media types — application/x-www-form-urlencoded and multipart/form-data:
# OpenAPI 3.x
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
6. JSON Schema alignment
Swagger 2.0 used an older JSON Schema draft. OpenAPI 3.0 switched to a near-draft-05 superset; OpenAPI 3.1 is fully aligned with JSON Schema 2020-12. If you have validators or codegen that target a specific JSON Schema dialect, the same $ref and type definitions may validate differently across 3.0 and 3.1.
7. Webhooks (3.1)
OpenAPI 3.1 added a top-level webhooks key:
webhooks:
newOrder:
post:
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Order"
responses:
"200": { description: OK }
Useful for describing GitHub-style webhook APIs without inventing your own structure.
A minimal spec, both versions
The same "list pets" endpoint in both formats, for comparison:
Swagger 2.0:
swagger: "2.0"
info:
title: Pet Store
version: 1.0.0
host: api.example.com
basePath: /v1
schemes: [https]
paths:
/pets:
get:
summary: List pets
responses:
"200":
description: OK
schema:
type: array
items:
$ref: "#/definitions/Pet"
definitions:
Pet:
type: object
required: [id, name]
properties:
id: { type: integer }
name: { type: string }
OpenAPI 3.1:
openapi: 3.1.0
info:
title: Pet Store
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/pets:
get:
summary: List pets
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Pet"
components:
schemas:
Pet:
type: object
required: [id, name]
properties:
id: { type: integer }
name: { type: string }
The shape is recognisable in both — same info, same paths, same responses. The differences are mechanical: swagger/openapi at the top, servers instead of host+basePath+schemes, components/schemas instead of definitions, and requestBody separate from parameters.
Validating a spec before you ship
A spec that parses is not a spec that's correct. A few checks that catch the embarrassing bugs before the docs go live:
- Top-level version field present.
swagger: "2.0"oropenapi: 3.x.y— without it, every toolchain rejects the file info.titleandinfo.versionset. Most renderers use these as the page heading and the version badge; missing fields produce blank docspathsis non-empty. An emptypaths:block describes no API; it's almost always a forgotten copy-paste- Every operation has a
responsesblock. Even a baredefault: { description: ... }is enough - Every
$refresolves. A broken$refis the most common spec defect; importers fail on it silently - No orphaned schemas. Components declared in
components/schemasbut never referenced via$ref— usually OK, but worth pruning - No
exampleused whereexamplesis required — in OpenAPI 3.x, the plural is an array; the singular is a single value. Codegen treats them very differently
The OpenAPI / Swagger Editor checks the structural ones — version field present, info block complete, paths non-empty — and surfaces the rest as a browsable list so you can audit them by eye.
For a deeper validation, the canonical tool is swagger-cli (swagger-cli validate openapi.yaml), which checks $ref resolution and a lot of the spec's internal consistency rules. Run it in CI on every PR.
Endpoint browsing
A spec is also a navigation aid. Once parsed, the operations table tells the whole story of an API:
GET /pets— list petsPOST /pets— create a petGET /pets/{id}— fetch a single petPUT /pets/{id}— update a petDELETE /pets/{id}— remove a pet
For each operation, the useful fields are:
summary— one-line description, used in tooltipsdescription— longer Markdown description, used in the docs pageoperationId— a stable identifier for codegen and routingtags— group operations into sections in the docs UIparameters— the inputs (path, query, header, cookie)requestBody— the body payload (OpenAPI 3.x)responses— every status code, with examples and schemas
The OpenAPI / Swagger Editor lists every operation with method, path, and summary, so you can browse a spec without spinning up Swagger UI.
JSON or YAML?
Both formats are equally valid for both versions. Pick whichever your team prefers and be consistent:
- YAML is more compact and easier to read; the official OpenAPI examples use YAML
- JSON is easier to generate programmatically and round-trips without quoting issues
If you're writing the spec by hand, YAML is more pleasant. If you're generating it from code or diffing it across many tools, JSON has fewer surprises. The editor accepts both and re-emits as JSON for a clean canonical view.
Common mistakes
- Mixing 2.0 and 3.x fields. A
definitionsblock in an OpenAPI 3.x file is silently ignored — no error, no warning, just a schemas section that's missing from the docs type: filefor uploads — valid in Swagger 2.0, removed in OpenAPI 3.x. Usetype: stringwithformat: binaryinsidemultipart/form-data- Forgetting
requestBodycontent type — everyrequestBodyneeds at least one entry undercontent:(e.g.application/json); the renderer needs to know what media type to advertise - Treating 3.0 and 3.1 as interchangeable — 3.1's full JSON Schema alignment breaks some 3.0 codegen that depends on the old behaviour. If you don't need 3.1 features, stay on 3.0.3
- Missing
operationId— codegen uses it for method names in client SDKs; auto-generated IDs collide across files
Everything stays in your browser
The OpenAPI / Swagger Editor parses with the standard js-yaml and JSON.parse libraries — locally, with no upload. That matters when the spec describes an internal API you don't want to leak, or when you want to inspect a third-party spec without pinging their servers.
Next steps
- Pretty-print a JSON spec: JSON Formatter
- Validate the YAML form before saving: YAML Validator
- Broader HTTP API tooling: curl vs Postman vs Hoppscotch
- JSON Schema and JSON best practices: JSON Formatting Best Practices