Skip to content
/ oasdiff Public
forked from Tufin/oasdiff

OpenAPI Diff and Breaking Changes

License

Notifications You must be signed in to change notification settings

jyggen/oasdiff

 
 

Repository files navigation

CI codecov Go Report Card GoDoc Docker Image Version

OpenAPI Diff

Command-line and Go package to compare and detect breaking changes in OpenAPI specs.

Try it

docker run --rm -t tufin/oasdiff -format text -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Features

Install with Go

go install github.com/tufin/oasdiff@latest

Install on macOS with Brew

brew tap tufin/homebrew-tufin
brew install oasdiff

Install on macOS, Windows and Linux

Copy binaries from latest release

Wrappers

Usage

  -base string
    	path or URL (or a glob in Composed mode) of original OpenAPI spec in YAML or JSON format
  -breaking-only
    	display breaking changes only (old method)
  -check-breaking
    	check for breaking changes (new method)
  -composed
    	work in 'composed' mode, compare paths in all specs matching base and revision globs
  -deprecation-days int
    	minimal number of days required between deprecating a resource and removing it without being considered 'breaking'
  -err-ignore string
    	the configuration file for ignoring errors with '-check-breaking'
  -exclude-description
    	ignore changes to descriptions (deprecated, use '-exclude-elements description' instead)
  -exclude-elements value
    	comma-separated list of elements to exclude from diff
  -exclude-endpoints
    	exclude endpoints from output (deprecated, use '-exclude-elements endpoints' instead)
  -exclude-examples
    	ignore changes to examples (deprecated, use '-exclude-elements examples' instead)
  -fail-on-diff
    	exit with return code 1 when any ERR-level breaking changes are found, used together with '-check-breaking'
  -fail-on-warns
    	exit with return code 1 when any WARN-level breaking changes are found, used together with '-check-breaking' and '-fail-on-diff'
  -filter string
    	if provided, diff will include only paths that match this regular expression
  -filter-extension string
    	if provided, diff will exclude paths and operations with an OpenAPI Extension matching this regular expression
  -format string
    	output format: yaml, json, text or html
  -help
    	display help
  -include-checks value
    	comma-separated list of optional breaking-changes checks
  -lang string
    	language for localized breaking changes checks errors (default "en")
  -max-circular-dep int
    	maximum allowed number of circular dependencies between objects in OpenAPI specs (default 5)
  -prefix string
    	deprecated. use '-prefix-revision' instead
  -prefix-base string
    	if provided, paths in original (base) spec will be prefixed with the given prefix before comparison
  -prefix-revision string
    	if provided, paths in revised (revision) spec will be prefixed with the given prefix before comparison
  -revision string
    	path or URL (or a glob in Composed mode) of revised OpenAPI spec in YAML or JSON format
  -strip-prefix-base string
    	if provided, this prefix will be stripped from paths in original (base) spec before comparison
  -strip-prefix-revision string
    	if provided, this prefix will be stripped from paths in revised (revision) spec before comparison
  -summary
    	display a summary of the changes instead of the full diff
  -version
    	show version and quit
  -warn-ignore string
    	the configuration file for ignoring warnings with '-check-breaking'

All arguments can be passed with one or two leading minus signs.
For example, -breaking-only and --breaking-only are equivalent.

Usage Examples

OpenAPI diff of local files in YAML

oasdiff -base data/openapi-test1.yaml -revision data/openapi-test2.yaml

The default output format is YAML.
No output means that the diff is empty, or, in other words, there are no changes.

OpenAPI diff of local files in Text/Markdown

oasdiff -format text -base data/openapi-test1.yaml -revision data/openapi-test2.yaml

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.

OpenAPI diff of local files in HTML

oasdiff -format html -base data/openapi-test1.yaml -revision data/openapi-test2.yaml

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.

OpenAPI diff for remote files over http/s

oasdiff -format text -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

OpenAPI breaking changes (new method)

oasdiff -check-breaking -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

OpenAPI breaking changes across multiple specs (new method)

oasdiff -check-breaking -composed -base "data/composed/base/*.yaml" -revision "data/composed/revision/*.yaml"

Fail with exit code 1 if a breaking change is found (new method)

oasdiff -fail-on-diff -check-breaking -composed -base "data/composed/base/*.yaml" -revision "data/composed/revision/*.yaml"

OpenAPI diff across multiple specs

oasdiff -composed -base "data/composed/base/*.yaml" -revision "data/composed/revision/*.yaml"

Fail with exit code 1 if any change is found

oasdiff -fail-on-diff -format text -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

OpenAPI diff for endpoints containing "/api" in the path

oasdiff -format text -filter "/api" -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

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"

Exclude paths and operations with extension "x-beta"

oasdiff -format text -filter-extension "x-beta" -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Notes:

  1. OpenAPI Extensions can be defined both at the path level and at the operation level. Both are matched and excluded with this flag.
  2. If a path or operation has a matching extension only in one of the specs, but not in the other, it will appear as Added or Deleted.

Ignore changes to description and examples

oasdiff -exclude-elements description,examples -format text -base data/openapi-test1.yaml -revision data/openapi-test3.yaml

Display change summary

oasdiff -summary -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Running with Docker

To run with docker just replace the oasdiff command by docker run --rm -t tufin/oasdiff, for example:

docker run --rm -t tufin/oasdiff -format text -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Breaking changes with Docker

docker run --rm -t tufin/oasdiff -check-breaking -base https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml -revision https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml

Comparing local files with Docker

docker run --rm -t -v $(pwd)/data:/data:ro tufin/oasdiff -base /data/openapi-test1.yaml -revision /data/openapi-test3.yaml

Replace $(pwd)/data by the path that contains your files.
Note that the -base and -revision paths must begin with /.

OpenAPI Diff and Breaking-Changes as a Service

You can use oasdiff as a service like this:

curl -X POST -F [email protected] -F [email protected] https://api.oasdiff.com/diff

Or, to see breaking changes:

curl -X POST -F [email protected] -F [email protected] https://api.oasdiff.com/breaking-changes

Service source code: https://github.com/oasdiff/oasdiff-service

Output Formats

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.

Paths vs. Endpoints

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:

In such cases, consider using -exclude-elements endpoints and -format json as a workaround.

Composed Mode

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.

This mode is a little different from a regular comparison of two specs to each-other:

  • compares only paths and endpoints, other resources are compared only if referenced from the paths or endpoints
  • compares each path/endpoint in 'base' to its equivalent in 'revision'
  • if any endpoint appears more than once in 'base' or 'revision', then we use the endpoint with the most recent x-since-date value
  • the x-since-date extension should be set on Path or Operation level
  • x-since-date extensions set on the Operation level override the value set on Path level
  • if an endpoint doesn't have the x-since-date extension, its value is set to the default: "2000-01-01"
  • duplicate endpoints with the same x-since-date value will trigger an error
  • the format of the x-since-date is the RFC3339 full-date format

Example of the x-since-date usage:

/api/test:
 get:
  x-since-date: "2023-01-11"

Note: Composed mode doesn't support Path Prefix Modification

Path Prefix Modification

Sometimes paths prefixes need to be modified, for example, to create a new version:

  • /api/v1/...
  • /api/v2/...

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 -base original.yaml -revision new.yaml -strip-prefix-base /api/v1 -prefix-base /api/v2

or

oasdiff -base original.yaml -revision new.yaml -strip-prefix-base /api/v1 -strip-prefix-revision /api/v2

Note that stripping precedes prepending.

Excluding Specific Kinds of Changes

You can use the -exclude-elements flag to exclude certain kinds of changes:

  • Use -exclude-elements changes to exclude Examples
  • Use -exclude-elements description to exclude description fields
  • Use -exclude-elements title to exclude title fields
  • Use -exclude-elements summary to exclude summary fields
  • Use -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.
Note that Extensions are always excluded from the diff.

Notes for Go Developers

Embedding oasdiff into your program

diff.Get(&diff.Config{}, spec1, spec2)

Code Examples

OpenAPI References

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.

Requests for enhancements

  1. OpenAPI 3.1 support: see Tufin#52

If you have other ideas, please let us know.

Credits

This project relies on the excellent implementation of OpenAPI 3.0 for Go: kin-openapi

About

OpenAPI Diff and Breaking Changes

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • Go 99.8%
  • Other 0.2%