OpenAPI Diff
Compares two OpenAPI documents and separates breaking changes from additive ones.
Compares two versions of an OpenAPI document and separates the changes into breaking and additive. The rule it uses is written on the page: a change is breaking if a request the old document accepted might now be rejected, or a response it promised is one an existing client can no longer handle.
Previous document
Drop the previous version
Read in this tab only.
New document
Drop the new version
Read in this tab only.
Breaking
8
Additive
7
Verdict
Needs a major version
GET /pets
- breakingThe `in: query` parameter `limit` is now required.
- addedAn optional `in: query` parameter `sort` was added.
- changedThe summary or description changed.
GET /pets · responses["200"].content["application/json"]
- breaking`[].id` changed type from integer to string.
- breakingThe property `[].name` is now optional.
- breaking`[].status` gained the enum value "pending".
- addedAn optional property `[].owner` was added.
GET /pets/{petId} · responses["200"].content["application/json"]
- breaking`id` changed type from integer to string.
- breakingThe property `name` is now optional.
- breaking`status` gained the enum value "pending".
- addedAn optional property `owner` was added.
GET /pets/{petId}
- breakingThe `404` response is gone.
DELETE /pets/{petId}
- addedThe operation was added.
components.schemas.Owner
- addedThe schema was added.
info.version
- changed`1.0.0` → `2.0.0`
What counts as breaking
In one sentence: a request the previous document accepted might now be rejected, or a response it promised is one an existing client can no longer handle. So: removing a path, an operation, a response code, a media type or a response property; adding a required parameter or required request property; optional becoming required; a type change; removing a request enum value; adding a response enum value (the client’s switch has no case for it); and a response property going from required to optional. The opposite directions, and changes to descriptions, tags, operationId and deprecated flags, are compatible.
- · Schemas are compared after following
$refwithin the document, so renaming a component is not a change. Path parameters are matched by position rather than by name. - · The insides of
oneOf·anyOf·notare compared as a whole and reported as breaking if they differ — this does not reason about them. - · A
$refpointing at another file is not followed. Bundle the files into one first.
To check a single document, use OpenAPI lint.
How to use it
Put the old and new documents side by side
JSON or YAML for either. Both are parsed in this tab, so an unreleased spec does not leave your machine.
Read the verdict
Breaking count, additive count, and what that means for the version number: a major bump, a minor one, or nothing at all because the contract is unchanged.
Filter to the breaking ones and read them
Grouped by operation, each with what changed. The Markdown copy is shaped for a pull-request description.
Common questions
Why is adding a response enum value breaking?
Because an existing client has a switch with no case for it. Adding to a *request* enum is safe — the server accepts more than before; adding to a response enum sends clients something they were never told about. The direction is what decides it.
I renamed a component and it reports no change.
Correct. Schemas are compared after following `$ref`, so a renamed component with the same shape is the same contract. Names in `components` are internal; clients see the resolved shape.
Is a required response property becoming optional really breaking?
Yes, from the client’s side. It was promised the field would always be there and its code reads it unconditionally; making it optional means the server may now omit it. Required and optional swap directions between request and response, which is the part people get backwards.
How does it handle `oneOf` and `anyOf`?
They are compared as a whole and reported as breaking if they differ at all. Reasoning about whether one union is a superset of another is a decision procedure this deliberately does not attempt; a false "breaking" you can dismiss is better than a false "safe" you cannot.
Feed it from
JSON Diff
Compares two JSON documents structurally, ignoring key order and reporting added, removed and changed paths.
OpenAPI Linter
Checks an OpenAPI document for missing responses, unused schemas, references that point at nothing and the other faults that break code generators.
Semver Range Tester
Checks which versions satisfy a range, compares two versions and sorts a list in precedence order.
JSON Formatter & Validator
Pretty-prints, minifies and validates JSON, pointing at the exact line and column of a syntax error.
Next
These accept what this tool produces, so the result can go straight in.
JSON Diff
Compares two JSON documents structurally, ignoring key order and reporting added, removed and changed paths.
JSON Schema Validator
Validates a document against a JSON Schema and reports each failure with its instance path.
OpenAPI Linter
Checks an OpenAPI document for missing responses, unused schemas, references that point at nothing and the other faults that break code generators.
Semver Range Tester
Checks which versions satisfy a range, compares two versions and sorts a list in precedence order.
JSON ⇄ CSV
Flattens nested JSON into columns or rebuilds objects from a table, with a dot-path column naming rule.
JSON Formatter & Validator
Pretty-prints, minifies and validates JSON, pointing at the exact line and column of a syntax error.