Skip to content

Commit 1eef2dc

Browse files
author
Chris Wiechmann
committed
Cache the validationResult for the originalPath is no match is found
#2
1 parent 83369bb commit 1eef2dc

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def invoke(msg)
3131
def apiId = msg.get("api.id");
3232
// Get/Create an OpenAPIValidator instance based on the API-ID
3333
def validator = OpenAPIValidator.getInstance(apiId, "apiadmin", "changeme");
34+
35+
// Optionally you can configure an internal cache. For more details please see:
36+
// https://github.com/Axway-API-Management-Plus/openapi-validator/issues/2
37+
// validator.getExposurePath2SpecifiedPathMap().setMaxSize(5000);
38+
3439
// Get required parameters for the validation
3540
def payload = bodyAsString(msg.get('content.body'));
3641
def path = msg.get("http.request.path");

src/main/java/com/axway/apim/openapi/validator/OpenAPIValidator.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class OpenAPIValidator
3131

3232
private OpenApiInteractionValidator validator;
3333

34-
private MaxSizeHashMap<String, String> exposurePath2SpecifiedPathMap = new MaxSizeHashMap<String, String>();
34+
private MaxSizeHashMap<String, Object> exposurePath2SpecifiedPathMap = new MaxSizeHashMap<String, Object>();
3535

3636
private int payloadLogMaxLength = 40;
3737

@@ -96,7 +96,7 @@ public boolean isValidRequest(String payload, String verb, String path, QueryStr
9696
Utils.traceMessage("Validate request: [verb: "+verb+", path: '"+path+"', payload: '"+Utils.getContentStart(payload, payloadLogMaxLength, true)+"']", TraceLevel.INFO);
9797
ValidationReport validationReport = null;
9898
String originalPath = path;
99-
// The given path might be the FE-API exposed path which is not always part of the API-Specification.
99+
// The given path might be the FE-API exposure path which is not guaranteed to be part of the API-Specification.
100100
// If for example the Petstore is exposed with /petstore/v3 the path we get might be /petstore/v3/store/order/78787
101101
// and with that, the validation fails, as the specification doesn't contain this path.
102102
// The following code nevertheless tries to find the matching API path by removing the first part of the path and
@@ -105,11 +105,19 @@ public boolean isValidRequest(String payload, String verb, String path, QueryStr
105105
boolean cachePath = false;
106106
// Perhaps the path has already looked up and matched to the specified path (e.g. /petstore/v3/store/order/78787 --> /store/order/{orderId}
107107
if(exposurePath2SpecifiedPathMap.containsKey(path)) {
108-
// In that case perform the validation based on the cached path
109-
validationReport = validateRequest(payload, verb, exposurePath2SpecifiedPathMap.get(path), queryParams, headers);
108+
if(exposurePath2SpecifiedPathMap.get(path) instanceof ValidationReport) {
109+
// Previously with the given we got a validation error, just return the same again
110+
validationReport = (ValidationReport)exposurePath2SpecifiedPathMap.get(path);
111+
} else {
112+
// In that case perform the validation based on the cached path
113+
validationReport = validateRequest(payload, verb, (String)exposurePath2SpecifiedPathMap.get(path), queryParams, headers);
114+
}
110115
} else {
111116
// Otherwise try to find the belonging specified path
112117
for(int i=0; i<5;i++) {
118+
if(cachePath) {
119+
Utils.traceMessage("Retrying validation with reduced path: '"+path+"']' ("+i+"/5)", TraceLevel.INFO);
120+
}
113121
validationReport = validateRequest(payload, verb, path, queryParams, headers);
114122
if(validationReport.hasErrors()) {
115123
if(validationReport.getMessages().toString().contains("No API path found that matches request")) {
@@ -125,7 +133,12 @@ public boolean isValidRequest(String payload, String verb, String path, QueryStr
125133
}
126134
}
127135
if(cachePath) {
128-
exposurePath2SpecifiedPathMap.put(originalPath, path);
136+
if(validationReport.hasErrors() && validationReport.getMessages().toString().contains("No API path found that matches request")) {
137+
// Finally no match found, cache the returned validation report
138+
exposurePath2SpecifiedPathMap.put(originalPath, validationReport);
139+
} else {
140+
exposurePath2SpecifiedPathMap.put(originalPath, path);
141+
}
129142
}
130143
}
131144

@@ -248,7 +261,7 @@ public void setMaxSize(int maxSize) {
248261
}
249262
}
250263

251-
public MaxSizeHashMap<String, String> getExposurePath2SpecifiedPathMap() {
264+
public MaxSizeHashMap<String, Object> getExposurePath2SpecifiedPathMap() {
252265
return exposurePath2SpecifiedPathMap;
253266
}
254267
}

src/test/java/com/axway/apim/openapi/validator/TestOpenAPIValidator.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,22 @@ public void invalidRequestWithFullPathAndPathParameter() throws IOException
126126
Assert.assertFalse(validator.isValidRequest(null, verb, path, null, headers));
127127
}
128128

129+
@Test
130+
public void invalidRequestNoMatchToSpec() throws IOException
131+
{
132+
String swagger = Files.readFile(this.getClass().getClassLoader().getResourceAsStream(TEST_PACKAGE + "PetstoreSwagger2.0.json"));
133+
OpenAPIValidator validator = OpenAPIValidator.getInstance(swagger);
134+
135+
String path = "/api/petstore/will/never/map/should/be/cached/anyway";
136+
String verb = "GET";
137+
HeaderSet headers = new HeaderSet();
138+
headers.addHeader("Content-Type", "application/json");
139+
140+
Assert.assertFalse(validator.isValidRequest(null, verb, path, null, headers));
141+
// This time, it should be cached anyway
142+
Assert.assertFalse(validator.isValidRequest(null, verb, path, null, headers));
143+
}
144+
129145
@Test
130146
public void validRequestExternalURLSwagger20() throws IOException
131147
{

0 commit comments

Comments
 (0)