Skip to content

Commit 779a012

Browse files
committed
Add possibility to override API path matching strategy
Fixes #823
1 parent 354e4d2 commit 779a012

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.openapitools.openapidiff.core.compare.matchers;
2+
3+
import io.swagger.v3.oas.models.Operation;
4+
import io.swagger.v3.oas.models.PathItem;
5+
import io.swagger.v3.oas.models.parameters.Parameter;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Objects;
10+
import java.util.Optional;
11+
import java.util.Set;
12+
import java.util.stream.IntStream;
13+
14+
/** Default implementation of PathMatcher */
15+
public class DefaultPathMatcher implements PathMatcher {
16+
17+
private static final String REGEX_PATH = "\\{([^/{}]+)}";
18+
19+
@Override
20+
public Optional<Map.Entry<String, PathItem>> find(
21+
Map.Entry<String, PathItem> what, Map<String, PathItem> candidates) {
22+
String leftUrl = what.getKey();
23+
PathItem leftPath = what.getValue();
24+
25+
final String template = normalizePath(leftUrl);
26+
return candidates.entrySet().stream()
27+
.filter(item -> normalizePath(item.getKey()).equals(template))
28+
.min(
29+
(a, b) -> {
30+
if (methodsAndParametersIntersect(a.getValue(), b.getValue())) {
31+
throw new IllegalArgumentException(
32+
"Two path items have the same signature: " + template);
33+
}
34+
if (a.getKey().equals(leftUrl)) {
35+
return -1;
36+
} else if (b.getKey().equals(leftUrl)) {
37+
return 1;
38+
} else {
39+
HashSet<PathItem.HttpMethod> methodsA =
40+
new HashSet<>(a.getValue().readOperationsMap().keySet());
41+
methodsA.retainAll(leftPath.readOperationsMap().keySet());
42+
HashSet<PathItem.HttpMethod> methodsB =
43+
new HashSet<>(b.getValue().readOperationsMap().keySet());
44+
methodsB.retainAll(leftPath.readOperationsMap().keySet());
45+
return Integer.compare(methodsB.size(), methodsA.size());
46+
}
47+
});
48+
}
49+
50+
private static String normalizePath(String path) {
51+
return path.replaceAll(REGEX_PATH, "{}");
52+
}
53+
54+
private static boolean methodsAndParametersIntersect(PathItem a, PathItem b) {
55+
Set<PathItem.HttpMethod> methodsA = a.readOperationsMap().keySet();
56+
for (PathItem.HttpMethod method : b.readOperationsMap().keySet()) {
57+
if (methodsA.contains(method)) {
58+
Operation left = a.readOperationsMap().get(method);
59+
Operation right = b.readOperationsMap().get(method);
60+
if (left.getParameters().size() == right.getParameters().size()) {
61+
return parametersIntersect(left.getParameters(), right.getParameters());
62+
}
63+
return false;
64+
}
65+
}
66+
return false;
67+
}
68+
69+
private static boolean parametersIntersect(List<Parameter> left, List<Parameter> right) {
70+
int parametersSize = left.size();
71+
long intersectedParameters =
72+
IntStream.range(0, left.size())
73+
.filter(i -> parametersTypeEquals(left.get(i), right.get(i)))
74+
.count();
75+
return parametersSize == intersectedParameters;
76+
}
77+
78+
private static boolean parametersTypeEquals(Parameter left, Parameter right) {
79+
return Objects.equals(left.getSchema().getType(), right.getSchema().getType())
80+
&& Objects.equals(left.getSchema().getFormat(), right.getSchema().getFormat());
81+
}
82+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.openapitools.openapidiff.core.compare.matchers;
2+
3+
import io.swagger.v3.oas.models.PathItem;
4+
import java.util.Map;
5+
import java.util.Optional;
6+
7+
/** Strategy to find a matching path. */
8+
public interface PathMatcher {
9+
10+
/**
11+
* Finds a matching path entry.
12+
*
13+
* @param what entry of the path to find
14+
* @param candidates map of right spec paths to search in
15+
* @return Optional entry of the matching right path
16+
*/
17+
Optional<Map.Entry<String, PathItem>> find(
18+
Map.Entry<String, PathItem> what, Map<String, PathItem> candidates);
19+
}

0 commit comments

Comments
 (0)