README
¶
OpenAPI Diff
A diff tool for OpenAPI Spec 3.
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
- Generate a diff report in YAML, Text/Markdown or HTML
- Run from Docker
- Embed in your go program
- Compare specs from the file system or over http/s
- Compare specs in YAML or JSON format
- Comprehensive diff including all aspects of OpenAPI Specification: paths, operations, parameters, request bodies, responses, schemas, enums, callbacks, security etc.
- Detect breaking changes (Beta feature. Please report issues)
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
Usage
oasdiff -help
Usage of oasdiff:
-base string
path of original OpenAPI spec in YAML or JSON format
-breaking-only
display breaking changes only
-exclude-description
ignore changes to descriptions
-exclude-examples
ignore changes to examples
-fail-on-diff
fail with exit code 1 if a difference is found
-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, text or html (default "yaml")
-prefix string
if provided, paths in base spec will be compared with 'prefix'+paths in revision spec
-revision string
path of revised OpenAPI spec in YAML or JSON format
-summary
display a summary of the changes instead of the full diff
All arguments can be passed with one or two leading minus signs.
For example -breaking-only and --breaking-only are equivalent.
Usage Examples
YAML diff of local files
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.
Text/Markdown diff of local files
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.
HTML diff of local files
oasdiff -format text -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.
Diff 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
Display breaking changes only
oasdiff -breaking-only -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 are relative to the client. For example, a deleted endpoint or a new required property in the request body.
Fail with exit code 1 if a 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
Fail with exit code 1 if a breaking change is found
oasdiff -fail-on-diff -breaking-only -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
Display changes to 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:
- OpenAPI Extensions can be defined both at the path level and at the operation level. Both are matched and excluded with this flag.
- 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 descriptions and examples
oasdiff -exclude-description -exclude-examples -format text -base data/openapi-test1.yaml -revision data/openapi-test3.yaml
Display change summary
oasdiff -breaking-only -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
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 /.
Output example - Text/Markdown
oasdiff -format text -base data/openapi-test1.yaml -revision data/openapi-test5.yaml
New Endpoints: None
Deleted Endpoints: 2
POST /register POST /subscribe
Modified Endpoints: 2
GET /api/{domain}/{project}/badges/security-score
- Modified query param: filter
- Content changed
- Modified media type: application/json
- Schema changed
- Required changed
- New required property: type
- Required changed
- Schema changed
- Modified media type: application/json
- Content changed
- Modified query param: image
- Examples changed
- Deleted example: 0
- Examples changed
- Modified query param: token
- Schema changed
- MaxLength changed from 29 to null
- Schema changed
- Modified header param: user
- Schema changed
- Schema added
- Content changed
- Deleted media type: application/json
- Schema changed
- Modified cookie param: test
- Content changed
- Modified media type: application/json
- Schema changed
- Type changed from 'object' to 'string'
- Schema changed
- Modified media type: application/json
- Content changed
- Responses changed
- New response: default
- Deleted response: 200
- Modified response: 201
- Content changed
- Modified media type: application/xml
- Schema changed
- Type changed from 'string' to 'object'
- Schema changed
- Modified media type: application/xml
- Content changed
GET /api/{domain}/{project}/install-command
- Deleted header param: network-policies
- Responses changed
- Modified response: default
- Description changed from 'Tufin1' to 'Tufin'
- Headers changed
- Deleted header: X-RateLimit-Limit
- Modified response: default
- Servers changed
- New server: https://www.tufin.io/securecloud
Security Requirements changed
- Deleted security requirements: bearerAuth
Servers changed
- Deleted server: tufin.com
Output example - YAML
oasdiff -base data/openapi-test1.yaml -revision data/openapi-test5.yaml
info:
title:
from: Tufin
to: Tufin1
contact:
added: true
license:
added: true
version:
from: 1.0.0
to: 1.0.1
paths:
deleted:
- /register
- /subscribe
modified:
/api/{domain}/{project}/badges/security-score:
operations:
modified:
GET:
tags:
deleted:
- security
parameters:
modified:
cookie:
test:
content:
mediaTypeModified:
application/json:
schema:
type:
from: object
to: string
header:
user:
schema:
schemaAdded: true
content:
mediaTypeDeleted:
- application/json
query:
filter:
content:
mediaTypeModified:
application/json:
schema:
required:
stringsdiff:
added:
- type
image:
examples:
deleted:
- "0"
token:
schema:
maxLength:
from: 29
to: null
responses:
added:
- default
deleted:
- "200"
modified:
"201":
content:
mediaTypeModified:
application/xml:
schema:
type:
from: string
to: object
parameters:
deleted:
path:
- domain
/api/{domain}/{project}/install-command:
operations:
modified:
GET:
parameters:
deleted:
header:
- network-policies
responses:
modified:
default:
description:
from: Tufin1
to: Tufin
headers:
deleted:
- X-RateLimit-Limit
servers:
added:
- https://www.tufin.io/securecloud
endpoints:
deleted:
- method: POST
path: /register
- method: POST
path: /subscribe
modified:
? method: GET
path: /api/{domain}/{project}/install-command
: parameters:
deleted:
header:
- network-policies
responses:
modified:
default:
description:
from: Tufin1
to: Tufin
headers:
deleted:
- X-RateLimit-Limit
servers:
added:
- https://www.tufin.io/securecloud
? method: GET
path: /api/{domain}/{project}/badges/security-score
: tags:
deleted:
- security
parameters:
modified:
cookie:
test:
content:
mediaTypeModified:
application/json:
schema:
type:
from: object
to: string
header:
user:
schema:
schemaAdded: true
content:
mediaTypeDeleted:
- application/json
query:
filter:
content:
mediaTypeModified:
application/json:
schema:
required:
stringsdiff:
added:
- type
image:
examples:
deleted:
- "0"
token:
schema:
maxLength:
from: 29
to: null
responses:
added:
- default
deleted:
- "200"
modified:
"201":
content:
mediaTypeModified:
application/xml:
schema:
type:
from: string
to: object
security:
deleted:
- bearerAuth
servers:
deleted:
- tufin.com
tags:
deleted:
- security
- reuven
externalDocs:
deleted: true
components:
schemas:
added:
- requests
modified:
network-policies:
additionalPropertiesAllowed:
from: true
to: false
rules:
additionalPropertiesAllowed:
from: null
to: false
parameters:
deleted:
header:
- network-policies
headers:
deleted:
- new
modified:
test:
schema:
additionalPropertiesAllowed:
from: true
to: false
testc:
content:
mediaTypeModified:
application/json:
schema:
type:
from: object
to: string
requestBodies:
deleted:
- reuven
responses:
added:
- default
deleted:
- OK
securitySchemes:
deleted:
- OAuth
modified:
AccessToken:
type:
from: http
to: oauth2
scheme:
from: bearer
to: ""
OAuthFlows:
added: true
Notes
-
Output Formats
- The default output format, YAML, provides a full view of all diff details.
Note that no output in 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.
If you wish to include additional details in non-YAML formats, please open an issue.
- The default output format, YAML, provides a full view of all diff details.
-
Paths vs. Endpoints
OpenAPI Specification has a hierarchial model of Paths and Operations (HTTP methods).
oasdiff respects this heirarchy and displays a hierarchial 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: - securityThe 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, for example, python's PyYAML. Here's possible solution.
-
AllOf, AnyOf, OneOf
OpenAPI Specification allows you to combine schemas using AllOf, AnyOf, OneOf keywords. Calculating the diff for these keywords is challenging because they consist of lists of schemas without keys which prevents association of corresponding schemas in ‘base’ and ‘revision’ specifications. oasdiff tries to work around this limitation by using $ref as the schema key when possible. In other cases, when the schema is defined inline, without a $ref, oasdiff may not be able to accurately identify the changes.
Notes for Go Developers
-
Embedding oasdiff into your program is easy:
diff.Get(&diff.Config{}, spec1, spec2)See full example: main.go
-
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. -
Use configuration to exclude certain types of changes:
- Examples
- Descriptions
- Extensions are excluded by default
Work in progress
- Patch support: currently supports Descriptions and a few fields in Schema
Requests for enhancements
- OpenAPI 3.1 support: see https://github.com/Tufin/oasdiff/issues/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
Documentation
¶
There is no documentation for this package.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package diff provides a diff function for OpenAPI Spec 3.
|
Package diff provides a diff function for OpenAPI Spec 3. |
|
Package load provides a function to load an OpenAPI spec from a URL or a Path
|
Package load provides a function to load an OpenAPI spec from a URL or a Path |
|
Package report generates OpenAPI Spec diff reports as text and HTML.
|
Package report generates OpenAPI Spec diff reports as text and HTML. |