Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ testDiff.md
testDeprecatedApi.html
testNewApi.html


.vscode/

.DS_Store
1 change: 1 addition & 0 deletions Example/petstore_v3_testResponseRender.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Changelog</title><script type="text/javascript">function showHide(id){if(document.getElementById(id).style.display=='none'){document.getElementById(id).style.display='block';document.getElementById('btn_'+id).innerHTML='&uArr;';}else{document.getElementById(id).style.display='none';document.getElementById('btn_'+id).innerHTML='&dArr;';}return true;}</script><link rel="stylesheet" href="http://deepoove.com/swagger-diff/stylesheets/demo.css"></head><body><header><h1>Changelog</h1></header><div class="article"><div><h2>Versions<a id="btn_versions" class="showhide" href="#" onClick="javascript:showHide(&#x27;versions&#x27;)">&uArr;</a></h2><hr><p id="versions">Changes from 1.0 to 1.1.</p></div><div><h2>What&#x27;s New<a id="btn_new" class="showhide" href="#" onClick="javascript:showHide(&#x27;new&#x27;)">&uArr;</a></h2><hr><ol id="new"><li><span class="get">GET</span>/admin/item <span></span></li><li><span class="post">POST</span>/admin/item <span></span></li><li><span class="get">GET</span>/item <span></span></li></ol></div><div><h2>What&#x27;s Deprecated<a id="btn_deprecated" class="showhide" href="#" onClick="javascript:showHide(&#x27;deprecated&#x27;)">&uArr;</a></h2><hr><ol id="deprecated"></ol></div><div><h2>What&#x27;s Changed<a id="btn_changed" class="showhide" href="#" onClick="javascript:showHide(&#x27;changed&#x27;)">&uArr;</a></h2><hr><ol id="changed"><li><span class="post">POST</span>/item <span></span><ul class="detail"><li><h3>Return Type</h3><ul class="change response"><li>Change id<span class="comment"> (Data Type)</span></li></ul></li><li><h3>Produces</h3><ul class="change produces"><li>Add application/xml<span></span></li></ul></li><li><h3>Responses</h3><ul class="change responses"><li>Add response 201<span class="comment">//created</span></li><li>Add response 400<span class="comment">//bad request</span></li><li class="missing">Delete response <del>404</del><span class="comment">//bad request</span></li><li>Response 200<ul class="change response-detail"><li>Description <del class="comment">ok</del> change into <span class="comment">update Success</span></li><li>Change id<span class="comment"> (Data Type)</span></li><li>Add content-type application/xml</li><li>Add header X-New-Header</li><li class="missing">Delete header <del>X-Deprecated-Header</del></li><li>Change header X-Rate-Limit</li></ul></li></ul></li></ul></li></ol></div></div></body></html>
1 change: 1 addition & 0 deletions Example/testDiff.json

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Build Status](https://travis-ci.org/Sayi/swagger-diff.svg?branch=master) ![jdk1.8+](https://img.shields.io/badge/jdk-1.8%2B-orange.svg) [![Coverage Status](https://coveralls.io/repos/github/Sayi/swagger-diff/badge.svg)](https://coveralls.io/github/Sayi/swagger-diff) [![Maven](https://maven-badges.herokuapp.com/maven-central/com.deepoove/swagger-diff/badge.svg?style=plastic)](https://maven-badges.herokuapp.com/maven-central/com.deepoove/swagger-diff)

Compare two swagger API specifications(1.x or v2.0) and render the difference to html file or markdown file.
Compare two swagger/openAPI API specifications(1.x or v2.0 or openAPI 3.0.x) and render the difference to html file or markdown file.

## :black_large_square: Command line interface (CLI)

Expand All @@ -15,7 +15,7 @@ Usage: java -jar swagger-diff.jar [options]
* -new
new api-doc location:Json file path or Http url
-v
swagger version:1.0 or 2.0
swagger version:1.0 or 2.0 or 3.0
Default: 2.0
-output-mode
render mode: markdown or html
Expand All @@ -36,7 +36,7 @@ java -jar swagger-diff.jar \
Download the fatJar or view the changelog on the **[Release Page](https://github.com/Sayi/swagger-diff/releases),** and thanks to all contributors.

## Feature
* Supports swagger spec v1.x and v2.0.
* Supports swagger spec v1.x v2.0 and openAPI 3.0.x
* Depth comparison of parameters, responses, notes, http method(GET,POST,PUT,DELETE...)
* Supports swagger api Authorization
* Render difference of property with Expression Language
Expand All @@ -48,13 +48,13 @@ Download the fatJar or view the changelog on the **[Release Page](https://github
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>swagger-diff</artifactId>
<version>1.2.2</version>
<version>1.3.0</version>
</dependency>
```

## Gradle
```shell
compile group: 'com.deepoove', name: 'swagger-diff', version: '1.2.2'
compile group: 'com.deepoove', name: 'swagger-diff', version: '1.3.0'
```

## Usage
Expand All @@ -73,6 +73,11 @@ v2.0
SwaggerDiff.compareV2("petstore_v2_1.json", "petstore_v2_2.json");
```

openAPI 3.0.x
```java
SwaggerDiff.compareV3("petstore_v3_1.json", "petstore_v3_2.json");
```

## Render difference
#### HTML
```java
Expand Down Expand Up @@ -157,7 +162,3 @@ try {

## How it works
![image](./swagger-diff.png)




64 changes: 58 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>com.deepoove</groupId>
<artifactId>swagger-diff</artifactId>
<version>1.2.2</version>
<version>1.3.0</version>
<packaging>jar</packaging>

<name>swagger-diff</name>
Expand Down Expand Up @@ -57,14 +57,14 @@

<dependencies>
<dependency>
<groupId>io.swagger</groupId>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser</artifactId>
<version>1.0.31</version>
<version>2.1.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-compat-spec-parser</artifactId>
<version>1.0.31</version>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.j2html</groupId>
Expand Down Expand Up @@ -93,6 +93,11 @@
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>

<profiles>
Expand Down Expand Up @@ -199,6 +204,53 @@
<artifactId>coveralls-maven-plugin</artifactId>
<version>4.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.deepoove.swagger.diff.cli.CLI</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.deepoove.swagger.diff.cli.CLI</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<!-- prepara l'agent prima dei test -->
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- genera il report dopo i test -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Binary file added src/.DS_Store
Binary file not shown.
149 changes: 59 additions & 90 deletions src/main/java/com/deepoove/swagger/diff/SwaggerDiff.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.deepoove.swagger.diff;

import java.io.IOException;
import java.util.List;

import org.slf4j.Logger;
Expand All @@ -9,129 +8,99 @@
import com.deepoove.swagger.diff.compare.SpecificationDiff;
import com.deepoove.swagger.diff.model.ChangedEndpoint;
import com.deepoove.swagger.diff.model.Endpoint;
import com.fasterxml.jackson.databind.JsonNode;

import io.swagger.models.Swagger;
import io.swagger.models.auth.AuthorizationValue;
import io.swagger.parser.SwaggerCompatConverter;
import io.swagger.parser.SwaggerParser;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;

public class SwaggerDiff {

public static final String SWAGGER_VERSION_V2 = "2.0";
public static final String OPENAPI_VERSION_V3 = "3.0";

private static Logger logger = LoggerFactory.getLogger(SwaggerDiff.class);

private Swagger oldSpecSwagger;
private Swagger newSpecSwagger;
private OpenAPI oldSpecSwagger;
private OpenAPI newSpecSwagger;

private List<Endpoint> newEndpoints;
private List<Endpoint> missingEndpoints;
private List<ChangedEndpoint> changedEndpoints;

/**
* compare two swagger 1.x doc
*
* @param oldSpec
* old api-doc location:Json or Http
* @param newSpec
* new api-doc location:Json or Http
*/
public static SwaggerDiff compareV1(String oldSpec, String newSpec) {
return compare(oldSpec, newSpec, null, null);
}

/**
* compare two swagger v2.0 doc
*
* @param oldSpec
* old api-doc location:Json or Http
* @param newSpec
* new api-doc location:Json or Http
* Compare two OpenAPI/Swagger documents (supports both Swagger 2.0 and OpenAPI 3.x).
*
* @param oldSpec old api-doc location: file path or HTTP URL
* @param newSpec new api-doc location: file path or HTTP URL
*/
public static SwaggerDiff compareV2(String oldSpec, String newSpec) {
return compare(oldSpec, newSpec, null, SWAGGER_VERSION_V2);
return compare(oldSpec, newSpec);
}


/**
* compare two swagger v2.0 Sring
* Compare two OpenAPI 3.x documents.
*
* @param oldSpec old api-doc json as string
* @param newSpec new api-doc json as string
* @param oldSpec old api-doc location: file path or HTTP URL
* @param newSpec new api-doc location: file path or HTTP URL
*/
public static SwaggerDiff compareV2Raw(String oldSpec, String newSpec) {
return new SwaggerDiff(oldSpec, newSpec).compare();
public static SwaggerDiff compareV3(String oldSpec, String newSpec) {
return compare(oldSpec, newSpec);
}

/**
* Compare two swagger v2.0 docs by JsonNode
*
* @param oldSpec
* old Swagger specification document in v2.0 format as a JsonNode
* @param newSpec
* new Swagger specification document in v2.0 format as a JsonNode
* Compare two OpenAPI/Swagger documents from raw JSON/YAML strings.
*/
public static SwaggerDiff compareV2(JsonNode oldSpec, JsonNode newSpec) {
return new SwaggerDiff(oldSpec, newSpec).compare();
public static SwaggerDiff compareRaw(String oldSpec, String newSpec) {
return new SwaggerDiff(oldSpec, newSpec, true).compare();
}

public static SwaggerDiff compare(String oldSpec, String newSpec,
List<AuthorizationValue> auths, String version) {
return new SwaggerDiff(oldSpec, newSpec, auths, version).compare();
/** @deprecated Use compareV2 or compareV3 */
@Deprecated
public static SwaggerDiff compareV2Raw(String oldSpec, String newSpec) {
return compareRaw(oldSpec, newSpec);
}

public static SwaggerDiff compare(String oldSpec, String newSpec) {
return new SwaggerDiff(oldSpec, newSpec, false).compare();
}

/**
* @param rawOldSpec
* @param rawNewSpec
*/
private SwaggerDiff(String rawOldSpec, String rawNewSpec) {
SwaggerParser swaggerParser = new SwaggerParser();
oldSpecSwagger = swaggerParser.parse(rawOldSpec);
newSpecSwagger = swaggerParser.parse(rawNewSpec);
// ---- Constructors ----

if (null == oldSpecSwagger || null == newSpecSwagger) {
throw new RuntimeException("cannot read api-doc from spec.");
}
}
/** Constructor for file path / URL */
private SwaggerDiff(String oldSpec, String newSpec, boolean isRawContent) {
ParseOptions options = new ParseOptions();
options.setResolve(true);
options.setResolveFully(true);

/**
* @param oldSpec
* @param newSpec
* @param auths
* @param version
*/
private SwaggerDiff(String oldSpec, String newSpec, List<AuthorizationValue> auths,
String version) {
if (SWAGGER_VERSION_V2.equals(version)) {
SwaggerParser swaggerParser = new SwaggerParser();
oldSpecSwagger = swaggerParser.read(oldSpec, auths, true);
newSpecSwagger = swaggerParser.read(newSpec, auths, true);
} else {
SwaggerCompatConverter swaggerCompatConverter = new SwaggerCompatConverter();
try {
oldSpecSwagger = swaggerCompatConverter.read(oldSpec, auths);
newSpecSwagger = swaggerCompatConverter.read(newSpec, auths);
} catch (IOException e) {
logger.error("cannot read api-doc from spec[version_v1.x]", e);
return;
}
OpenAPIParser parser = new OpenAPIParser();

SwaggerParseResult oldResult = isRawContent
? parser.readContents(oldSpec, null, options)
: parser.readLocation(oldSpec, null, options);
SwaggerParseResult newResult = isRawContent
? parser.readContents(newSpec, null, options)
: parser.readLocation(newSpec, null, options);

oldSpecSwagger = oldResult.getOpenAPI();
newSpecSwagger = newResult.getOpenAPI();

if (oldResult.getMessages() != null && !oldResult.getMessages().isEmpty()) {
logger.warn("Warnings parsing old spec: {}", oldResult.getMessages());
}
if (newResult.getMessages() != null && !newResult.getMessages().isEmpty()) {
logger.warn("Warnings parsing new spec: {}", newResult.getMessages());
}
if (null == oldSpecSwagger || null == newSpecSwagger) { throw new RuntimeException(
"cannot read api-doc from spec."); }
}

private SwaggerDiff(JsonNode oldSpec, JsonNode newSpec) {
SwaggerParser swaggerParser = new SwaggerParser();
oldSpecSwagger = swaggerParser.read(oldSpec, true);
newSpecSwagger = swaggerParser.read(newSpec, true);
if (null == oldSpecSwagger || null == newSpecSwagger) { throw new RuntimeException(
"cannot read api-doc from spec."); }
if (null == oldSpecSwagger || null == newSpecSwagger) {
throw new RuntimeException("Cannot read api-doc from spec. " +
"Old: " + oldResult.getMessages() +
" New: " + newResult.getMessages());
}
}

private SwaggerDiff compare() {
SpecificationDiff diff = SpecificationDiff.diff(oldSpecSwagger, newSpecSwagger);
SpecificationDiff diff = SpecificationDiff.diff(oldSpecSwagger, newSpecSwagger);
this.newEndpoints = diff.getNewEndpoints();
this.missingEndpoints = diff.getMissingEndpoints();
this.changedEndpoints = diff.getChangedEndpoints();
Expand All @@ -151,10 +120,10 @@ public List<ChangedEndpoint> getChangedEndpoints() {
}

public String getOldVersion() {
return oldSpecSwagger.getInfo().getVersion();
return oldSpecSwagger.getInfo() != null ? oldSpecSwagger.getInfo().getVersion() : "unknown";
}

public String getNewVersion() {
return newSpecSwagger.getInfo().getVersion();
return newSpecSwagger.getInfo() != null ? newSpecSwagger.getInfo().getVersion() : "unknown";
}
}
Loading