Skip to content

Commit cb7aecf

Browse files
committed
Added custom json renderer to return values
1 parent 3f83920 commit cb7aecf

File tree

6 files changed

+220
-49
lines changed

6 files changed

+220
-49
lines changed

frontend/app/components/diff-viewer.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ interface DiffNode {
3939
isExpanded?: boolean
4040
}
4141

42+
interface Resp {
43+
display: DiffNode
44+
}
45+
4246
export default function DiffViewer({ file1, file2, onClose }: DiffViewerProps) {
4347
const [diffTree, setDiffTree] = useState<DiffNode | null>(null)
4448
const [isLoading, setIsLoading] = useState(true)
@@ -60,7 +64,7 @@ export default function DiffViewer({ file1, file2, onClose }: DiffViewerProps) {
6064
previous: file1.content,
6165
current: file2.content
6266
}).then((response) => {
63-
result = response.data as DiffNode
67+
result = response.data as Resp
6468

6569
// Initially expand all nodes that have changes
6670
const nodesToExpand = new Set<string>()
@@ -75,11 +79,11 @@ export default function DiffViewer({ file1, file2, onClose }: DiffViewerProps) {
7579
}
7680
}
7781
// Calculate metrics
78-
const calculatedMetrics = calculateMetrics(result)
82+
const calculatedMetrics = calculateMetrics(result.display)
7983
setMetrics(calculatedMetrics)
80-
collectExpandedNodes(result)
84+
collectExpandedNodes(result.display)
8185
setExpandedNodes(nodesToExpand)
82-
setDiffTree(result)
86+
setDiffTree(result.display)
8387
setIsLoading(false)
8488
})
8589

@@ -239,7 +243,6 @@ export default function DiffViewer({ file1, file2, onClose }: DiffViewerProps) {
239243
const renderMetricsView = () => {
240244
const { added, removed, changed, unchanged, total } = metrics
241245
const changedTotal = added + removed + changed
242-
const changedPercentage = total > 0 ? Math.round((changedTotal / total) * 100) : 0
243246

244247
return (
245248
<div className="p-4">

src/main/java/com/APIprotector/apiprotector/Controller/HelloController.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/main/java/com/APIprotector/apiprotector/Config.java renamed to src/main/java/com/APIprotector/apiprotector/config/Config.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.APIprotector.apiprotector;
1+
package com.APIprotector.apiprotector.config;
22

33
import jakarta.servlet.http.HttpServletRequest;
44
import org.springframework.context.annotation.Configuration;
@@ -46,5 +46,4 @@ public Resource resolveResource(HttpServletRequest request, String requestPath,
4646
}
4747
});
4848
}
49-
5049
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
package com.APIprotector.apiprotector.Controller;
1+
package com.APIprotector.apiprotector.controller;
22

3-
import com.APIprotector.apiprotector.service.DiffNode;
4-
import com.APIprotector.apiprotector.service.JsonComparator;
5-
import com.fasterxml.jackson.databind.JsonNode;
3+
import com.APIprotector.apiprotector.library.CompositeDiff;
64
import org.springframework.http.MediaType;
75
import org.springframework.web.bind.annotation.PostMapping;
86
import org.springframework.web.bind.annotation.RequestBody;
97
import org.springframework.web.bind.annotation.RequestMapping;
108
import org.springframework.web.bind.annotation.RestController;
119
import java.io.IOException;
1210

13-
import java.util.List;
1411
import java.util.Map;
1512
import com.fasterxml.jackson.databind.ObjectMapper;
16-
import com.APIprotector.apiprotector.service.DiffGenerator;
1713

1814
@RestController
1915
@RequestMapping("/api/diff")
@@ -32,10 +28,6 @@ public String getSpecsToDiff(@RequestBody Map<String, Object> map) throws IOExce
3228
String previousAsString = objectMapper.writeValueAsString(previous);
3329
String currentAsString = objectMapper.writeValueAsString(current);
3430

35-
36-
JsonNode diff = JsonComparator.compareJsonNodes(objectMapper.readTree(previousAsString), objectMapper.readTree(currentAsString), "", "");
37-
38-
// DiffNode diff = DiffGenerator.generateUnifiedDiff((Map<String, Object>) previous, (Map<String, Object>) current);
39-
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(diff);
31+
return new CompositeDiff(previousAsString, currentAsString).toString();
4032
}
4133
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.APIprotector.apiprotector.library;
2+
3+
import com.APIprotector.apiprotector.service.JsonComparator;
4+
import com.fasterxml.jackson.annotation.JsonIgnore;
5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
import com.fasterxml.jackson.core.JsonProcessingException;
7+
import com.fasterxml.jackson.databind.JsonNode;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.ObjectWriter;
10+
import org.openapitools.openapidiff.core.OpenApiCompare;
11+
import org.openapitools.openapidiff.core.model.ChangedOpenApi;
12+
13+
import java.io.ByteArrayOutputStream;
14+
import java.io.OutputStreamWriter;
15+
16+
17+
public class CompositeDiff {
18+
@JsonIgnore
19+
private static final JsonRenderer jsonRenderer = new JsonRenderer();
20+
@JsonIgnore
21+
private static final ObjectMapper objectMapper = new ObjectMapper();
22+
@JsonIgnore
23+
private static final ObjectWriter objectWriter = objectMapper
24+
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
25+
.writer();
26+
27+
private final JsonNode display;
28+
private final JsonNode changes;
29+
30+
public CompositeDiff(String previous, String current) throws JsonProcessingException {
31+
ChangedOpenApi diff = OpenApiCompare.fromContents(previous, current);
32+
33+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
34+
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
35+
jsonRenderer.render(diff, outputStreamWriter);
36+
37+
display = JsonComparator.compareJsonNodes(objectMapper.readTree(previous), objectMapper.readTree(current), "", "");
38+
changes = objectMapper.readTree(outputStream.toString());
39+
}
40+
41+
@Override
42+
public String toString() {
43+
try {
44+
return objectWriter.writeValueAsString(this);
45+
} catch (JsonProcessingException e) {
46+
throw new RuntimeException(e);
47+
}
48+
}
49+
50+
public JsonNode getDisplay() {
51+
return display;
52+
}
53+
54+
public JsonNode getChanges() {
55+
return changes;
56+
}
57+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package com.APIprotector.apiprotector.library;
2+
3+
import io.swagger.v3.oas.models.parameters.Parameter;
4+
import org.openapitools.openapidiff.core.exception.RendererException;
5+
import org.openapitools.openapidiff.core.model.*;
6+
import org.openapitools.openapidiff.core.output.Render;
7+
8+
import java.io.IOException;
9+
import java.io.OutputStreamWriter;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Optional;
13+
14+
import com.fasterxml.jackson.databind.ObjectMapper;
15+
16+
import java.util.*;
17+
18+
public class JsonRenderer implements Render {
19+
protected ChangedOpenApi diff;
20+
21+
public JsonRenderer() {
22+
}
23+
24+
@Override
25+
public void render(ChangedOpenApi diff, OutputStreamWriter outputStreamWriter) {
26+
this.diff = diff;
27+
28+
Map<String, Object> result = new LinkedHashMap<>();
29+
30+
if (diff.isUnchanged()) {
31+
result.put("message", "No differences. Specifications are equivalent.");
32+
} else {
33+
result.put("title", diff.getNewSpecOpenApi().getInfo().getTitle());
34+
result.put("compatible", diff.isCompatible());
35+
36+
result.put("newEndpoints", endpointsToList(diff.getNewEndpoints()));
37+
result.put("missingEndpoints", endpointsToList(diff.getMissingEndpoints()));
38+
result.put("deprecatedEndpoints", endpointsToList(diff.getDeprecatedEndpoints()));
39+
result.put("changedOperations", changedOperationsToList(diff.getChangedOperations()));
40+
}
41+
42+
ObjectMapper objectMapper = new ObjectMapper();
43+
try {
44+
objectMapper.writerWithDefaultPrettyPrinter().writeValue(outputStreamWriter, result);
45+
outputStreamWriter.close();
46+
} catch (IOException e) {
47+
throw new RendererException(e);
48+
}
49+
}
50+
51+
private List<Map<String, Object>> endpointsToList(List<Endpoint> endpoints) {
52+
List<Map<String, Object>> list = new ArrayList<>();
53+
if (endpoints != null) {
54+
for (Endpoint endpoint : endpoints) {
55+
Map<String, Object> item = new LinkedHashMap<>();
56+
item.put("method", endpoint.getMethod().toString());
57+
item.put("path", endpoint.getPathUrl());
58+
item.put("summary", endpoint.getSummary());
59+
list.add(item);
60+
}
61+
}
62+
return list;
63+
}
64+
65+
private List<Map<String, Object>> changedOperationsToList(List<ChangedOperation> operations) {
66+
List<Map<String, Object>> list = new ArrayList<>();
67+
if (operations != null) {
68+
for (ChangedOperation op : operations) {
69+
Map<String, Object> item = new LinkedHashMap<>();
70+
item.put("method", op.getHttpMethod().toString());
71+
item.put("path", op.getPathUrl());
72+
item.put("summary", Optional.ofNullable(op.getSummary()).map(ChangedMetadata::getRight).orElse(""));
73+
74+
if (Changed.result(op.getParameters()).isDifferent()) {
75+
item.put("parameters", paramChanges(op.getParameters()));
76+
}
77+
78+
if (op.resultRequestBody().isDifferent()) {
79+
item.put("requestBody", contentChanges(op.getRequestBody().getContent()));
80+
}
81+
82+
if (op.resultApiResponses().isDifferent()) {
83+
item.put("responses", responseChanges(op.getApiResponses()));
84+
}
85+
86+
list.add(item);
87+
}
88+
}
89+
return list;
90+
}
91+
92+
private List<Map<String, Object>> paramChanges(ChangedParameters changedParams) {
93+
List<Map<String, Object>> params = new ArrayList<>();
94+
95+
for (Parameter param : changedParams.getIncreased()) {
96+
params.add(Map.of("action", "add", "name", param.getName(), "in", param.getIn()));
97+
}
98+
99+
for (ChangedParameter changed : changedParams.getChanged()) {
100+
String action = changed.isDeprecated() ? "deprecated" : "changed";
101+
Parameter newParam = changed.getNewParameter();
102+
params.add(Map.of("action", action, "name", newParam.getName(), "in", newParam.getIn()));
103+
}
104+
105+
for (Parameter param : changedParams.getMissing()) {
106+
params.add(Map.of("action", "delete", "name", param.getName(), "in", param.getIn()));
107+
}
108+
109+
return params;
110+
}
111+
112+
private List<Map<String, Object>> contentChanges(ChangedContent changedContent) {
113+
List<Map<String, Object>> content = new ArrayList<>();
114+
if (changedContent == null) return content;
115+
116+
changedContent.getIncreased().forEach((type, value) ->
117+
content.add(Map.of("action", "add", "contentType", type)));
118+
119+
changedContent.getMissing().forEach((type, value) ->
120+
content.add(Map.of("action", "delete", "contentType", type)));
121+
122+
changedContent.getChanged().forEach((type, mediaType) ->
123+
content.add(Map.of(
124+
"action", "change",
125+
"contentType", type,
126+
"compatible", mediaType.isCompatible()
127+
)));
128+
129+
return content;
130+
}
131+
132+
private List<Map<String, Object>> responseChanges(ChangedApiResponse responses) {
133+
List<Map<String, Object>> result = new ArrayList<>();
134+
135+
responses.getIncreased().forEach((code, value) ->
136+
result.add(Map.of("action", "add", "code", code)));
137+
138+
responses.getMissing().forEach((code, value) ->
139+
result.add(Map.of("action", "delete", "code", code)));
140+
141+
responses.getChanged().forEach((code, changed) -> {
142+
Map<String, Object> entry = new LinkedHashMap<>();
143+
entry.put("action", "change");
144+
entry.put("code", code);
145+
entry.put("mediaTypes", contentChanges(changed.getContent()));
146+
result.add(entry);
147+
});
148+
149+
return result;
150+
}
151+
}

0 commit comments

Comments
 (0)