A diff tool for OpenAPI Spec 3.
- 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)
go install github.com/tufin/oasdiff@latest
brew tap tufin/homebrew-tufin
brew install oasdiff
Copy binaries from latest release
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.
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.
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.
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.
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
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
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
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
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
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.
oasdiff -exclude-description -exclude-examples -format text -base data/openapi-test1.yaml -revision data/openapi-test3.yaml
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
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
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 /
.
oasdiff -format text -base data/openapi-test1.yaml -revision data/openapi-test5.yaml
POST /register POST /subscribe
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
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
-
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: - 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, for example, python's PyYAML. Here's possible solution.
-
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
- Patch support: currently supports Descriptions and a few fields in Schema
- OpenAPI 3.1 support: see Tufin#52
If you have other ideas, please let us know.
This project relies on the excellent implementation of OpenAPI 3.0 for Go: kin-openapi