OpenAPI Diff and Breaking Changes
Command-line and Go package to compare and detect breaking changes in OpenAPI specs.
docker run --rm -t tufin/oasdiff changelog https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test5.yaml
go install github.com/tufin/oasdiff@latest
brew tap tufin/homebrew-tufin
brew install oasdiff
Copy binaries from latest release
oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml
The default diff output format is YAML.
No output means that the diff is empty, or, in other words, there are no changes.
oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml -f text
The Text/Markdown diff report provides a simplified and partial view of the changes.
To view all details, use the default format: YAML.
If you'd like to see additional details in the text/markdown report, please submit a feature request.
oasdiff diff data/openapi-test1.yaml data/openapi-test2.yaml -f html
The HTML diff report provides a simplified and partial view of the changes.
To view all details, use the default format: YAML.
If you'd like to see additional details in the HTML report, please submit a feature request.
oasdiff diff https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f text
oasdiff breaking https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml
oasdiff breaking https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f yaml
oasdiff breaking "data/composed/base/*.yaml" "data/composed/revision/*.yaml" -c
oasdiff breaking "data/composed/base/*.yaml" "data/composed/revision/*.yaml" -c -o ERR
oasdiff diff https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f text -o
oasdiff changelog https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml
oasdiff diff https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f text -p "/api"
Filters are applied recursively at all levels. For example, if a path contains a callback, the filter will be applied both to the path itself and to the callback path. To include such a nested change, use a regular expression that contains both paths, for example -filter "path|callback-path"
oasdiff diff https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f text --filter-extension "x-beta"
Notes:
oasdiff diff data/openapi-test1.yaml data/openapi-test3.yaml --exclude-elements description,examples -f text
oasdiff summary https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml
To run with docker just replace the oasdiff
command by docker run --rm -t tufin/oasdiff
, for example:
docker run --rm -t tufin/oasdiff diff https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml -f text
docker run --rm -t tufin/oasdiff breaking https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml
docker run --rm -t -v $(pwd)/data:/data:ro tufin/oasdiff diff /data/openapi-test1.yaml /data/openapi-test3.yaml
Replace $(pwd)/data
by the path that contains your files.
Note that the spec paths must begin with /
.
Oasdiff is also available as a service.
The default diff output format, YAML, provides a full view of all diff details.
Note that no output in the YAML format signifies that the diff is empty, or, in other words, there are no changes.
Other formats: text, markdown, and HTML, are designed to be more user-friendly by providing only the most important parts of the diff, in a simplified format.
The JSON format works only with -exclude-elements endpoints
and is intended as a workaround for YAML complex mapping keys which aren't supported by some libraries (see comment at end of next section for more details).
If you wish to include additional details in non-YAML formats, please open an issue.
OpenAPI Specification has a hierarchical model of Paths and Operations (HTTP methods).
Oasdiff respects this hierarchy and displays a hierarchical diff with path changes: added, deleted and modified, and within the latter, "modified" section, another set of operation changes: added, deleted and modified. For example:
paths:
deleted:
- /register
- /subscribe
modified:
/api/{domain}/{project}/badges/security-score:
operations:
modified:
GET:
Oasdiff also outputs an alternate simplified diff per "endpoint" which is a combination of Path + Operation, for example:
endpoints:
deleted:
- method: POST
path: /subscribe
- method: POST
path: /register
modified:
? method: GET
path: /api/{domain}/{project}/badges/security-score
: tags:
deleted:
- security
The modified endpoints section has two items per key, method and path, this is called a complex mapping key in YAML.
Some YAML libraries don't support complex mapping keys:
When using output format json
, oasdiff excludes endpoints
automatically.
Composed mode compares two collections of OpenAPI specs instead of a pair of specs in the default mode. The collections are specified using a glob. This can be useful when your APIs are defined across multiple files, for example, when multiple services, each one with its own spec, are exposed behind an API gateway, and you want to check changes across all the specs at once.
Notes:
Sometimes paths prefixes need to be modified, for example, to create a new version:
Oasdiff allows comparison of API specifications with modified prefixes by stripping and/or prepending path prefixes.
In the example above you could compare the files as follows:
oasdiff diff original.yaml new.yaml --strip-prefix-base /api/v1 --prefix-base /api/v2
or
oasdiff diff original.yaml new.yaml --strip-prefix-base /api/v1 --strip-prefix-revision /api/v2
Note that stripping precedes prepending.
Sometimes developers decide to change names of path parameters, for example, in order to follow a certain naming convention.
Oasdiff supports path parameter renaming by default.
Learn more about how oasdiff supports path parameter renaming.
Header names comparison is normally case-sensitive.
To make this comparison case-insensitive, add the --case-insensitive-headers
flag:
oasdiff diff data/header-case/base.yaml data/header-case/revision.yaml --case-insensitive-headers
You can use the --exclude-elements
flag to exclude certain kinds of changes:
--exclude-elements examples
to exclude Examples
--exclude-elements extensions
to exclude Extensions
--exclude-elements description
to exclude description fields--exclude-elements title
to exclude title fields--exclude-elements summary
to exclude summary fields--exclude-elements endpoints
to exclude the endpoints diff
You can ignore multiple elements with a comma-separated list of excluded elements as in this example.
You can filter endpoints in two ways:
--match-path
option to exclude paths that don't match the given regular expression, see example
--filter-extension
option to exclude paths and operations with an OpenAPI Extension matching the given regular expression, see example
Oasdiff tracks changes to OpenAPI extensions by default. To disable this, see Excluding Specific Kinds of Changes.
The diff format for OpenAPI extensions conforms with JavaScript Object Notation (JSON) Patch, for example:
endpoints:
modified:
? method: POST
path: /example/callback
: extensions:
modified:
x-amazon-apigateway-integration:
- oldValue: "201"
value: "200"
op: replace
from: ""
path: /responses/default/statusCode
- oldValue: http://api.example.com/v1/example/callback
value: http://api.example.com/v1/example/calllllllllback
op: replace
from: ""
path: /uri
diff.Get(&diff.Config{}, spec1, spec2)
Oasdiff expects OpenAPI References to be resolved.
References are normally resolved automatically when you load the spec. In other cases you can resolve refs using Loader.ResolveRefsIn.
If you have other ideas, please let us know.
This project relies on the excellent implementation of OpenAPI 3.0 for Go: kin-openapi.