Compare two OpenAPI specifications (3.x) and render the difference to HTML plain text, Markdown files, or JSON files.
Available on Maven Central
<dependency>
<groupId>org.openapitools.openapidiff</groupId>
<artifactId>openapi-diff-core</artifactId>
<version>${openapi-diff-version}</version>
</dependency>
Available for Mac users on brew
brew install openapi-diff
Usage instructions in Usage -> Command line
Available on Docker Hub as openapitools/openapi-diff.
# docker run openapitools/openapi-diff:latest
usage: openapi-diff <old> <new>
--asciidoc <file> export diff as asciidoc in given file
--debug Print debugging information
--error Print error information
--fail-on-changed Fail if API changed but is backward
compatible
--fail-on-incompatible Fail only if API changes broke backward
compatibility
--config-file Config file to override default behavior. Supported file formats: .yaml
--config-prop Config property to override default behavior with key:value format (e.g. my.prop:true)
-h,--help print this message
--header <property=value> use given header for authorisation
--html <file> export diff as html in given file
--info Print additional information
--json <file> export diff as json in given file
-l,--log <level> use given level for log (TRACE, DEBUG,
INFO, WARN, ERROR, OFF). Default: ERROR
--markdown <file> export diff as markdown in given file
--off No information printed
--query <property=value> use query param for authorisation
--state Only output diff state: no_changes,
incompatible, compatible
--text <file> export diff as text in given file
--trace be extra verbose
--version print the version information and exit
--warn Print warning information
This is only required if you want to try new changes in the Dockerfile of this project.
docker build -t local-openapi-diff .
You can replace the local image name local-openapi-diff by any name of your choice.
In this example the $(pwd)/core/src/test/resources directory is mounted in the /specs directory of the container
in readonly mode (ro).
docker run --rm -t \
-v $(pwd)/core/src/test/resources:/specs:ro \
openapitools/openapi-diff:latest /specs/path_1.yaml /specs/path_2.yaml
The remote name openapitools/openapi-diff can be replaced with local-openapi-diff or the name you gave to your local image.
openapi-diff can read OpenAPI specs from JSON files or HTTP URLs.
$ openapi-diff --help
usage: openapi-diff <old> <new>
--asciidoc <file> export diff as asciidoc in given file
--debug Print debugging information
--error Print error information
-h,--help print this message
--header <property=value> use given header for authorisation
--html <file> export diff as html in given file
--info Print additional information
--json <file> export diff as json in given file
-l,--log <level> use given level for log (TRACE, DEBUG,
INFO, WARN, ERROR, OFF). Default: ERROR
--markdown <file> export diff as markdown in given file
--off No information printed
--query <property=value> use query param for authorisation
--state Only output diff state: no_changes,
incompatible, compatible
--fail-on-incompatible Fail only if API changes broke backward compatibility
--fail-on-changed Fail if API changed but is backward compatible
--config-file Config file to override default behavior. Supported file formats: .yaml
--config-prop Config property to override default behavior with key:value format (e.g. my.prop:true)
--trace be extra verbose
--version print the version information and exit
--warn Print warning information
Add openapi-diff to your POM to show diffs when you test your Maven project. You may opt to throw an error if you have broken backwards compatibility or if your API has changed.
<plugin>
<groupId>org.openapitools.openapidiff</groupId>
<artifactId>openapi-diff-maven</artifactId>
<version>${openapi-diff-version}</version>
<executions>
<execution>
<goals>
<goal>diff</goal>
</goals>
<configuration>
<oldSpec>https://petstore3.swagger.io/api/v3/openapi.json</oldSpec>
<newSpec>${project.basedir}/target/openapi.yaml</newSpec>
<failOnIncompatible>true</failOnIncompatible>
<failOnChanged>true</failOnChanged>
<consoleOutputFileName>${project.basedir}/../maven/target/diff.txt</consoleOutputFileName>
<jsonOutputFileName>${project.basedir}/../maven/target/diff.json</jsonOutputFileName>
<markdownOutputFileName>${project.basedir}/../maven/target/diff.md</markdownOutputFileName>
<configFiles>
<configFile>my/config-file.yaml</configFile>
</configFiles>
<configProps>
<incompatible.response.enum.increased>false</incompatible.response.enum.increased>
</configProps>
</configuration>
</execution>
</executions>
</plugin>
public class Main {
public static final String OPENAPI_DOC1 = "petstore_v3_1.json";
public static final String OPENAPI_DOC2 = "petstore_v2_2.yaml";
public static void main(String[] args) {
ChangedOpenApi diff = OpenApiCompare.fromLocations(OPENAPI_DOC1, OPENAPI_DOC2);
//...
}
}
Path matching controls how paths from the old and new specs are paired during comparison (PathsDiff.java). The default matcher (DefaultPathMatcher) obfuscates path parameter names, meaning /users/{id} matches /users/{userId}. The default matcher fails on ambiguous signatures if the spec contains a few paths semantically identical. In case this behaviour is not fitting your use case, you can implement your own matching strategy.
You can plug in a custom matcher via OpenApiDiffOptions implementing the PathMatcher interface:
OpenApiDiffOptions options = OpenApiDiffOptions
.builder()
.pathMatcher(new MyCustomPathMatcher())
.build();
ChangedOpenApi diff = OpenApiCompare.fromLocations(oldSpec, newSpec, null, options);
HtmlRender htmlRender = new HtmlRender("Changelog", "http://deepoove.com/swagger-diff/stylesheets/demo.css");
FileOutputStream outputStream = new FileOutputStream("testDiff.html");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
htmlRender.render(diff, outputStreamWriter);
MarkdownRender markdownRender = new MarkdownRender();
FileOutputStream outputStream = new FileOutputStream("testDiff.md");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
markdownRender.render(diff, outputStreamWriter);
AsciidocRender asciidocRender = new AsciidocRender();
FileOutputStream outputStream = new FileOutputStream("testDiff.adoc");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
asciidocRender.render(diff, outputStreamWriter);
JsonRender jsonRender = new JsonRender();
FileOutputStream outputStream = new FileOutputStream("testDiff.json");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
jsonRender.render(diff, outputStreamWriter);
This project uses Java Service Provider Interface (SPI) so additional extensions can be added.
To build your own extension, you simply need to create a src/main/resources/META-INF/services/org.openapitools.openapidiff.core.compare.ExtensionDiff file with the full classname of your implementation.
Your class must also implement the org.openapitools.openapidiff.core.compare.ExtensionDiff interface.
Then, including your library with the openapi-diff module will cause it to be triggered automatically.
Swagger Petstore
$ claude mcp add openapi-diff \
-- python -m otcore.mcp_server <graph>