");
sb.append("");
sb.append(entry.getValue().api.getInfo().getTitle());
diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java
index 0f1a6d41b..802129a8b 100644
--- a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptor.java
@@ -36,7 +36,6 @@
import static com.predic8.membrane.core.http.MimeType.*;
import static com.predic8.membrane.core.interceptor.Outcome.*;
import static com.predic8.membrane.core.openapi.util.OpenAPIUtil.*;
-import static com.predic8.membrane.core.openapi.util.UriUtil.*;
import static com.predic8.membrane.core.openapi.util.Utils.*;
public class OpenAPIPublisherInterceptor extends AbstractInterceptor {
@@ -83,7 +82,7 @@ public Outcome handleRequest(Exchange exc) throws Exception {
return handleOverviewOpenAPIDoc(exc);
}
- private Outcome handleOverviewOpenAPIDoc(Exchange exc) throws JsonProcessingException, URISyntaxException {
+ private Outcome handleOverviewOpenAPIDoc(Exchange exc) throws IOException, URISyntaxException {
Matcher m = patternMeta.matcher(exc.getRequest().getUri());
if (!m.matches()) { // No id specified
if (acceptsHtmlExplicit(exc)) {
@@ -119,95 +118,31 @@ private Outcome returnNoFound(Exchange exc, String id) {
return RETURN;
}
- private Outcome returnOpenApiAsYaml(Exchange exc, OpenAPIRecord rec) throws JsonProcessingException, URISyntaxException {
- rewriteOpenAPIaccordingToRequest(exc, rec);
+ private Outcome returnOpenApiAsYaml(Exchange exc, OpenAPIRecord rec) throws IOException, URISyntaxException {
+ rec.rewriteOpenAPI(exc, getRouter().getUriFactory());
exc.setResponse(Response.ok().contentType(APPLICATION_X_YAML).body(omYaml.writeValueAsBytes(rec.node)).build());
return RETURN;
}
- protected void rewriteOpenAPIaccordingToRequest(Exchange exc, OpenAPIRecord rec) throws URISyntaxException {
- rewriteOpenAPIVersion3(exc, rec);
- rewriteSwaggerVersion2(exc, rec);
- }
-
- private void rewriteSwaggerVersion2(Exchange exc, OpenAPIRecord rec) {
- // Rewrite OpenAPI 2.X
- JsonNode host = rec.node.get("host");
- if (host == null)
- return;
-
- String rewrittenHost = rewriteHost(exc);
- ((ObjectNode) rec.node).put("host", rewrittenHost);
-
- // Add protocol http or https
- ArrayNode schemes = ((ObjectNode) rec.node).putArray("schemes");
- schemes.add(getProtocol(exc));
-
- log.debug("Rewriting {} to {}", host, rewrittenHost);
- }
-
- private void rewriteOpenAPIVersion3(Exchange exc, OpenAPIRecord rec) throws URISyntaxException {
- JsonNode servers = rec.node.get("servers");
- if (servers == null)
- return;
-
- for (JsonNode server : servers) {
- String serverUrl = server.get("url").asText();
- String rewrittenUrl = rewriteUrl(exc, serverUrl);
- ((ObjectNode) server).put("url", rewrittenUrl);
- log.debug("Rewriting {} to {}", serverUrl, rewrittenUrl);
- }
- }
-
- /**
- * Rewrites URL from OpenAPI 3.X
- * @param exc Exchange
- * @param url URL to rewrite
- * @return Rewritten URL
- * @throws URISyntaxException syntax error ín URL
- */
- protected String rewriteUrl(Exchange exc, String url) throws URISyntaxException {
- return rewrite(router.getUriFactory(), url,
- getProtocol(exc),
- exc.getOriginalHostHeaderHost(),
- exc.getOriginalHostHeaderPort());
- }
-
- /**
- * Rewrites Host from Swagger 2.X
- * @param exc Exchange
- * @return Rewritten host with port
- */
- protected String rewriteHost(Exchange exc) {
- return exc.getOriginalHostHeaderHost() + ":" + exc.getOriginalHostHeaderPort();
- }
-
- private String getProtocol(Exchange exc) {
- if (exc.getRule().getSslInboundContext() == null)
- return "http";
- else
- return "https";
- }
-
private Outcome handleSwaggerUi(Exchange exc) {
Matcher m = patternUI.matcher(exc.getRequest().getUri());
// No id specified
if (!m.matches()) {
- Map details = new HashMap<>();
- details.put("message","Please specify an id of an OpenAPI document. Path should match this pattern: /api-doc/ui/<>");
- exc.setResponse(createProblemDetails(404,"/openapi/wrong-id","No OpenAPI document id",details));
+ Map details = new HashMap<>();
+ details.put("message", "Please specify an id of an OpenAPI document. Path should match this pattern: /api-doc/ui/<>");
+ exc.setResponse(createProblemDetails(404, "/openapi/wrong-id", "No OpenAPI document id", details));
return RETURN;
}
// /api-doc/ui/(.*)
String id = m.group(1);
- log.info("OpenAPI with id {} requested",id);
+ log.info("OpenAPI with id {} requested", id);
OpenAPIRecord record = apis.get(id);
if (record == null) {
- return returnNoFound(exc,id);
+ return returnNoFound(exc, id);
}
exc.setResponse(Response.ok().contentType(HTML_UTF_8).body(renderSwaggerUITemplate(id, record.api)).build());
diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecord.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecord.java
index ec1d28ac0..b0a6452e2 100644
--- a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecord.java
+++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecord.java
@@ -17,7 +17,13 @@
package com.predic8.membrane.core.openapi.serviceproxy;
import com.fasterxml.jackson.databind.*;
+import com.predic8.membrane.core.exchange.*;
+import com.predic8.membrane.core.util.*;
import io.swagger.v3.oas.models.*;
+import org.slf4j.*;
+
+import java.io.*;
+import java.net.*;
import static com.predic8.membrane.core.openapi.util.OpenAPIUtil.*;
@@ -33,15 +39,23 @@ public class OpenAPIRecord {
*/
JsonNode node;
+ OpenAPISpec spec;
+
/**
* Version of the OpenAPI standard e.g. 2.0, 3.0.1
*/
String version;
- public OpenAPIRecord(OpenAPI api, JsonNode node) {
+ /**
+ * Used for tests
+ */
+ public OpenAPIRecord() {}
+
+ public OpenAPIRecord(OpenAPI api, JsonNode node, OpenAPISpec spec) {
this.api = api;
this.node = node;
this.version = getOpenAPIVersion(node);
+ this.spec = spec;
}
public boolean isVersion2() {
@@ -51,4 +65,9 @@ public boolean isVersion2() {
public boolean isVersion3() {
return version.startsWith("3");
}
+
+ public JsonNode rewriteOpenAPI(Exchange exc, URIFactory uriFactory) throws URISyntaxException, IOException {
+ return spec.rewrite.rewrite(this,exc,uriFactory);
+ }
+
}
diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java
index e57e9d51a..66e4f415e 100644
--- a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java
+++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordFactory.java
@@ -31,7 +31,8 @@
import java.util.*;
import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.*;
-import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.Spec.YesNoOpenAPIOption.*;
+import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.ASINOPENAPI;
+import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.YES;
import static com.predic8.membrane.core.openapi.util.OpenAPIUtil.*;
import static com.predic8.membrane.core.util.FileUtil.*;
import static java.lang.String.*;
@@ -48,9 +49,9 @@ public OpenAPIRecordFactory(Router router) {
this.router = router;
}
- public Map create(Collection specs) throws IOException {
+ public Map create(Collection specs) throws IOException {
Map apiRecords = new LinkedHashMap<>();
- for (Spec spec : specs) {
+ for (OpenAPISpec spec : specs) {
// Maybe a spec has both location and dir.
addOpenApisFromLocation(apiRecords, spec);
addOpenApisFromDirectory(apiRecords, spec);
@@ -58,7 +59,7 @@ public Map create(Collection specs) throws IOExcept
return apiRecords;
}
- private void addOpenApisFromDirectory(Map apiRecords, Spec spec) throws IOException {
+ private void addOpenApisFromDirectory(Map apiRecords, OpenAPISpec spec) throws IOException {
if (spec.dir == null)
return;
@@ -75,7 +76,7 @@ private void addOpenApisFromDirectory(Map apiRecords, Spe
}
}
- private void addOpenApisFromLocation(Map apiRecords, Spec spec) {
+ private void addOpenApisFromLocation(Map apiRecords, OpenAPISpec spec) {
if (spec.location == null)
return;
@@ -112,19 +113,19 @@ private String getUniqueId(Map apiRecords, OpenAPIRecord
return id;
}
- private OpenAPIRecord create(Spec spec) throws IOException {
- OpenAPIRecord record = new OpenAPIRecord(getOpenAPI(router, spec), getSpec(router, spec));
+ private OpenAPIRecord create(OpenAPISpec spec) throws IOException {
+ OpenAPIRecord record = new OpenAPIRecord(getOpenAPI(router, spec), getSpec(router, spec),spec);
setExtentsionOnAPI(spec, record.api);
return record;
}
- private OpenAPIRecord create(Spec spec, File file) throws IOException {
- OpenAPIRecord record = new OpenAPIRecord(parseFileAsOpenAPI(file), getSpec(file));
+ private OpenAPIRecord create(OpenAPISpec spec, File file) throws IOException {
+ OpenAPIRecord record = new OpenAPIRecord(parseFileAsOpenAPI(file), getSpec(file),spec);
setExtentsionOnAPI(spec, record.api);
return record;
}
- private OpenAPI getOpenAPI(Router router, Spec spec) throws ResourceRetrievalException {
+ private OpenAPI getOpenAPI(Router router, OpenAPISpec spec) throws ResourceRetrievalException {
OpenAPI openAPI = new OpenAPIParser().readContents(readInputStream(getInputStreamForLocation(router, spec.location)),
null, null).getOpenAPI();
@@ -143,7 +144,7 @@ private InputStream getInputStreamForLocation(Router router, String location) th
return router.getResolverMap().resolve(ResolverMap.combine(router.getBaseLocation(), location));
}
- private JsonNode getSpec(Router router, Spec spec) throws IOException {
+ private JsonNode getSpec(Router router, OpenAPISpec spec) throws IOException {
return omYaml.readTree(getInputStreamForLocation(router, spec.location));
}
@@ -151,7 +152,7 @@ private JsonNode getSpec(File file) throws IOException {
return omYaml.readTree(file);
}
- private void setExtentsionOnAPI(Spec spec, OpenAPI api) {
+ private void setExtentsionOnAPI(OpenAPISpec spec, OpenAPI api) {
if (api.getExtensions() == null) {
api.setExtensions(new HashMap<>());
}
@@ -170,7 +171,7 @@ private Map getXValidationExtension(OpenAPI api) {
return extension;
}
- private Map updateExtension(Map extension, Spec spec) {
+ private Map updateExtension(Map extension, OpenAPISpec spec) {
if (spec.validationDetails != ASINOPENAPI)
extension.put(VALIDATION_DETAILS, toYesNo(spec.validationDetails));
@@ -187,7 +188,7 @@ private Map updateExtension(Map extension, Spec
return extension;
}
- private boolean toYesNo(Spec.YesNoOpenAPIOption option) {
+ private boolean toYesNo(OpenAPISpec.YesNoOpenAPIOption option) {
return option == YES;
}
diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java
new file mode 100644
index 000000000..970f20541
--- /dev/null
+++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPISpec.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2022 predic8 GmbH, www.predic8.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.predic8.membrane.core.openapi.serviceproxy;
+
+import com.predic8.membrane.annot.*;
+
+import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.ASINOPENAPI;
+
+/**
+ * @description Reads an OpenAPI description and deploys an API with the information of it.
+ */
+@MCElement(name = "openapi", topLevel = false)
+public class OpenAPISpec {
+
+ public String location;
+ public String dir;
+ public YesNoOpenAPIOption validateRequests = ASINOPENAPI;
+ YesNoOpenAPIOption validateResponses = ASINOPENAPI;
+ YesNoOpenAPIOption validationDetails = ASINOPENAPI;
+ Rewrite rewrite = new Rewrite();
+
+ public OpenAPISpec() {
+ }
+
+ @MCChildElement(order = 50)
+ public void setRewrite(Rewrite rewrite) {
+ this.rewrite = rewrite;
+ }
+
+ public Rewrite getRewrite() {
+ return rewrite;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ /**
+ * @description Filename or URL pointing to an OpenAPI document. Relative filenames use the %MEMBRANE_HOME%/conf folder as base directory.
+ * @example openapi/fruitstore-v1.yaml, https://api.predic8.de/shop/swagger
+ */
+ @MCAttribute()
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public String getDir() {
+ return dir;
+ }
+
+ /**
+ * @description Directory containing OpenAPI definitions to deploy.
+ * @example openapi
+ */
+ @MCAttribute()
+ public void setDir(String dir) {
+ this.dir = dir;
+ }
+
+ public YesNoOpenAPIOption getValidateRequests() {
+ return validateRequests;
+ }
+
+ /**
+ * @description Turn validation of requests on or off.
+ * @example yes
+ * @default no
+ */
+ @MCAttribute
+ public void setValidateRequests(YesNoOpenAPIOption validateRequests) {
+ this.validateRequests = validateRequests;
+ }
+
+ @SuppressWarnings("unused")
+ public YesNoOpenAPIOption getValidateResponses() {
+ return validateResponses;
+ }
+
+ /**
+ * @description Turn validation of responses on or off.
+ * @example yes
+ * @default no
+ */
+ @MCAttribute()
+ public void setValidateResponses(YesNoOpenAPIOption validateResponses) {
+ this.validateResponses = validateResponses;
+ }
+
+ /**
+ * @description Show details of the validation to the caller.
+ * @example yes
+ * @default no
+ */
+ @MCAttribute()
+ public void setValidationDetails(YesNoOpenAPIOption validationDetails) {
+ this.validationDetails = validationDetails;
+ }
+
+ public YesNoOpenAPIOption getValidationDetails() {
+ return validationDetails;
+ }
+
+ public enum YesNoOpenAPIOption {
+ YES,
+ NO,
+ ASINOPENAPI
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/Rewrite.java b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/Rewrite.java
new file mode 100644
index 000000000..c9b33741a
--- /dev/null
+++ b/core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/Rewrite.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2023 predic8 GmbH, www.predic8.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.predic8.membrane.core.openapi.serviceproxy;
+
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.node.*;
+import com.predic8.membrane.annot.*;
+import com.predic8.membrane.core.exchange.*;
+import com.predic8.membrane.core.openapi.util.*;
+import com.predic8.membrane.core.util.*;
+import org.slf4j.*;
+
+import java.io.*;
+import java.net.*;
+
+import static java.util.Objects.*;
+
+/**
+ * @description
+ */
+@MCElement(name = "rewrite", topLevel = false)
+public class Rewrite {
+
+ private static final Logger log = LoggerFactory.getLogger(Rewrite.class.getName());
+
+ Integer port;
+ String protocol;
+ String host;
+
+ public JsonNode rewrite(OpenAPIRecord rec, Exchange exc, URIFactory uriFactory) throws URISyntaxException, IOException {
+ if (rec.isVersion3())
+ return rewriteOpenAPI3(exc, uriFactory, rec.node);
+
+ return rewriteSwagger2(exc, rec.node);
+ }
+
+ private JsonNode rewriteOpenAPI3(Exchange exc, URIFactory uriFactory, JsonNode node) throws URISyntaxException {
+ // Expensive cloning before null check is fine cause most of OpenAPIs will have servers.
+ // Caching should not be needed cause the OpenAPI is not so often retrieved. Maybe practice
+ // will prove that wrong.
+ JsonNode rewritten = node.deepCopy();
+ for (JsonNode server : rewritten.get("servers")) {
+ rewriteServerEntry(exc, uriFactory, server);
+ }
+ return rewritten;
+ }
+
+ private void rewriteServerEntry(Exchange exc, URIFactory uriFactory, JsonNode server) throws URISyntaxException {
+ String url = server.get("url").asText();
+ String rewritten = rewriteUrl(exc, url, uriFactory);
+ ((ObjectNode) server).put("url", rewritten);
+ log.debug("Rewriting {} to {}", url, rewritten);
+ }
+
+ /**
+ * Rewrites URL from OpenAPI 3.X
+ *
+ * @param exc Exchange
+ * @param url URL to rewrite
+ * @param uriFactory URIFactory
+ * @return Rewritten URL
+ * @throws URISyntaxException syntax error ín URL
+ */
+ protected String rewriteUrl(Exchange exc, String url, URIFactory uriFactory) throws URISyntaxException {
+ return UriUtil.rewrite(uriFactory, url, rewriteProtocol(exc.getInboundProtocol()), rewriteHost(exc.getOriginalHostHeaderHost()), rewritePort(exc.getOriginalHostHeaderPort()));
+ }
+
+ private JsonNode rewriteSwagger2(Exchange exc, JsonNode node) {
+ JsonNode rewritten = node.deepCopy();
+ rewriteHostAndPortSwagger2(exc, rewritten);
+ rewriteSchemeSwagger2(exc, rewritten);
+ return rewritten;
+ }
+
+ private void rewriteSchemeSwagger2(Exchange exc, JsonNode node) {
+ // Add protocol http or https
+ ArrayNode schemes = ((ObjectNode) node).putArray("schemes");
+ schemes.add(exc.getInboundProtocol());
+ }
+
+ private void rewriteHostAndPortSwagger2(Exchange exc, JsonNode rewrittenJson) {
+ JsonNode host = rewrittenJson.get("host");
+ if (host == null)
+ return;
+
+ String rewrittenHost = getRewrittenHostAndPortSwagger2(exc);
+ ((ObjectNode) rewrittenJson).put("host", rewrittenHost);
+ log.debug("Rewriting {} to {}", host, rewrittenHost);
+ }
+
+ /**
+ * Rewrites Host from Swagger 2.X
+ *
+ * @param exc Exchange
+ * @return Rewritten host with port
+ */
+ protected String getRewrittenHostAndPortSwagger2(Exchange exc) {
+ return rewriteHost(exc.getOriginalHostHeaderHost()) + ":" + rewritePort(exc.getOriginalHostHeaderPort());
+ }
+
+ /**
+ * Rewrites the protocol if there was a value given.
+ *
+ * @param protocol from the OpenAPI
+ * @return rewritten value
+ */
+ public String rewriteProtocol(String protocol) {
+ return requireNonNullElse(this.protocol, protocol);
+ }
+
+ /**
+ * Rewrites the host if there was a value given.
+ *
+ * @param host from the OpenAPI
+ * @return rewritten value
+ */
+ public String rewriteHost(String host) {
+ return requireNonNullElse(this.host, host);
+ }
+
+ /**
+ * Rewrites the port if there was a value given.
+ *
+ * @param port from the OpenAPI
+ * @return rewritten value
+ */
+ public String rewritePort(String port) {
+ if (this.port != null) {
+ return this.port.toString();
+ }
+ return port;
+ }
+
+
+ public int getPort() {
+ return port;
+ }
+
+ @MCAttribute()
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ @MCAttribute()
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ @MCAttribute()
+ public void setHost(String host) {
+ this.host = host;
+ }
+}
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxyTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxyTest.java
index 8dad6b7cd..c876446ac 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxyTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxyTest.java
@@ -22,8 +22,9 @@
import java.util.*;
-import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.Spec.YesNoOpenAPIOption.*;
import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.*;
+import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.NO;
+import static com.predic8.membrane.core.openapi.serviceproxy.OpenAPISpec.YesNoOpenAPIOption.YES;
import static com.predic8.membrane.core.openapi.util.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
@@ -39,7 +40,7 @@ public void setUp() {
@Test
public void noOptionsNoExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/no-extensions.yml";
APIProxy proxy = createProxy(router,spec);
@@ -61,7 +62,7 @@ public void noOptionsNoExtensions() throws Exception {
@Test
public void validationRequestNoExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/no-extensions.yml";
spec.validateRequests = YES;
@@ -83,7 +84,7 @@ public void validationRequestNoExtensions() throws Exception {
@Test
public void validationResponsesNoExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/no-extensions.yml";
spec.validateResponses = YES;
@@ -106,7 +107,7 @@ public void validationResponsesNoExtensions() throws Exception {
@Test
public void validationAllNoExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/no-extensions.yml";
spec.validateRequests = YES;
spec.validateResponses = YES;
@@ -129,7 +130,7 @@ public void validationAllNoExtensions() throws Exception {
@Test
public void requestsExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/validate-requests-extensions.yml";
APIProxy proxy = createProxy(router,spec);
@@ -150,7 +151,7 @@ public void requestsExtensions() throws Exception {
@Test
public void responsesExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/validate-responses-extensions.yml";
APIProxy proxy = createProxy(router,spec);
@@ -172,7 +173,7 @@ public void responsesExtensions() throws Exception {
@Test
public void validationRequestNoDetailsNoExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/no-extensions.yml";
spec.validateRequests = YES;
spec.validationDetails = NO;
@@ -196,7 +197,7 @@ public void validationRequestNoDetailsNoExtensions() throws Exception {
@Test
public void validationDetailsFalseExtensions() throws Exception {
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = "src/test/resources/openapi/openapi-proxy/validation-details-false-extensions.yml";
spec.validateRequests = YES;
@@ -238,8 +239,8 @@ public void oneOpenAPIWithMultipleServerUrlsSharingTheSamePath() throws Exceptio
api.setSpecs(List.of(extracted("api-c-multiple-server-urls.yml")));
}
- private APIProxy.Spec extracted(String location) {
- APIProxy.Spec spec = new APIProxy.Spec();
+ private OpenAPISpec extracted(String location) {
+ OpenAPISpec spec = new OpenAPISpec();
spec.location = location;
return spec;
}
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptorTest.java
index 38461faea..ed667e189 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptorTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIInterceptorTest.java
@@ -29,8 +29,6 @@
import static com.predic8.membrane.core.http.MimeType.APPLICATION_JSON;
import static com.predic8.membrane.core.http.MimeType.APPLICATION_PROBLEM_JSON;
import static com.predic8.membrane.core.interceptor.Outcome.*;
-import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.Spec.YesNoOpenAPIOption.NO;
-import static com.predic8.membrane.core.openapi.serviceproxy.APIProxy.Spec.YesNoOpenAPIOption.YES;
import static com.predic8.membrane.core.openapi.util.JsonUtil.*;
import static com.predic8.membrane.core.openapi.util.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
@@ -39,9 +37,9 @@ public class OpenAPIInterceptorTest {
Router router;
- APIProxy.Spec specInfoServers;
- APIProxy.Spec specInfo3Servers;
- APIProxy.Spec specCustomers;
+ OpenAPISpec specInfoServers;
+ OpenAPISpec specInfo3Servers;
+ OpenAPISpec specCustomers;
Exchange exc = new Exchange(null);
OpenAPIInterceptor interceptor1Server;
@@ -52,13 +50,13 @@ public void setUp() throws Exception {
router = new Router();
router.setUriFactory(new URIFactory());
- specInfoServers = new APIProxy.Spec();
+ specInfoServers = new OpenAPISpec();
specInfoServers.location = "src/test/resources/openapi/specs/info-servers.yml";
- specInfo3Servers = new APIProxy.Spec();
+ specInfo3Servers = new OpenAPISpec();
specInfo3Servers.location = "src/test/resources/openapi/specs/info-3-servers.yml";
- specCustomers = new APIProxy.Spec();
+ specCustomers = new OpenAPISpec();
specCustomers.location = "src/test/resources/openapi/specs/customers.yml";
exc.setRequest(new Request.Builder().method("GET").build());
@@ -128,7 +126,7 @@ public void destinationsTargetSet() throws Exception {
@Test
public void validateRequest() throws Exception {
- specCustomers.validateRequests = YES;
+ specCustomers.validateRequests = OpenAPISpec.YesNoOpenAPIOption.YES;
Map customer = new HashMap<>();
customer.put("id","CUST-7");
@@ -151,20 +149,20 @@ public void validateRequest() throws Exception {
@SuppressWarnings({"unchecked"})
@Test
public void validateResponse() throws Exception {
- specCustomers.validateResponses = YES;
+ specCustomers.validateResponses = OpenAPISpec.YesNoOpenAPIOption.YES;
assertEquals("PUT", getMapFromResponse(callPut(specCustomers)).get("method"));
testValidationResults(getMapFromResponse(callPut(specCustomers)), "RESPONSE");
}
@Test
public void validateResponseLessDetails() throws Exception {
- specCustomers.validateResponses = YES;
- specCustomers.validationDetails = NO;
+ specCustomers.validateResponses = OpenAPISpec.YesNoOpenAPIOption.YES;
+ specCustomers.validationDetails = OpenAPISpec.YesNoOpenAPIOption.NO;
assertEquals("Message validation failed!", getMapFromResponse(callPut(specCustomers)).get("error"));
}
@NotNull
- private Exchange callPut(APIProxy.Spec spec) throws Exception {
+ private Exchange callPut(OpenAPISpec spec) throws Exception {
Exchange exc = new Exchange(null);
exc.setOriginalRequestUri("/customers");
exc.setRequest(new Request.Builder().method("PUT").url(new URIFactory(), "/customers").contentType(APPLICATION_JSON).build());
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java
index 38b3e5d04..7df3fc40e 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIPublisherInterceptorTest.java
@@ -27,7 +27,6 @@
import org.junit.jupiter.api.*;
import java.io.*;
-import java.net.*;
import java.util.*;
import static com.predic8.membrane.core.http.MimeType.*;
@@ -50,11 +49,11 @@ void setUp() throws Exception {
router.setUriFactory(new URIFactory());
router.setBaseLocation("");
openAPIRecordFactory = new OpenAPIRecordFactory(router);
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.setDir("src/test/resources/openapi/specs");
records = openAPIRecordFactory.create(Collections.singletonList(spec));
- interceptor = new OpenAPIPublisherInterceptor(records);
+ interceptor = new OpenAPIPublisherInterceptor( records);
interceptor.init(router);
get.setRequest(new Request.Builder().method("GET").build());
@@ -64,7 +63,7 @@ void setUp() throws Exception {
@Test
public void constuctor() {
- assertEquals(27, interceptor.apis.size());
+ assertTrue(interceptor.apis.size() >= 27);
assertNotNull(interceptor.apis.get("references-test-v1-0"));
assertNotNull(interceptor.apis.get("strings-test-api-v1-0"));
assertNotNull(interceptor.apis.get("extension-sample-v1-4"));
@@ -77,7 +76,7 @@ public void constuctor() {
public void getApiDirectory() throws Exception {
get.getRequest().setUri(OpenAPIPublisherInterceptor.PATH);
assertEquals( RETURN, interceptor.handleRequest(get));
- assertEquals(27, TestUtils.getMapFromResponse(get).size());
+ assertTrue(TestUtils.getMapFromResponse(get).size() >= 27);
}
@Test
@@ -134,39 +133,4 @@ public void getApiById() throws Exception {
private JsonNode getJsonFromYamlResponse(Exchange exc) throws IOException {
return omYaml.readTree(exc.getResponse().getBody().getContent());
}
-
- @Test
- public void rewriteOpenAPIAccordingToRequestTest() throws URISyntaxException {
- OpenAPIRecord rec = records.get("servers-1-api-v1-0");
- interceptor.rewriteOpenAPIaccordingToRequest(get, rec);
- assertEquals("http://api.predic8.de/base/v2",rec.node.get("servers").get(0).get("url").asText());
- assertEquals("Test System",rec.node.get("servers").get(0).get("description").asText());
- }
-
- @Test
- public void rewriteOpenAPIAccordingToRequest3Servers() throws URISyntaxException {
- OpenAPIRecord rec = records.get("servers-3-api-v1-0");
- interceptor.rewriteOpenAPIaccordingToRequest(get, rec);
- assertEquals(3,rec.node.get("servers").size());
- assertEquals("http://api.predic8.de/foo",rec.node.get("servers").get(0).get("url").asText());
- assertEquals("http://api.predic8.de/foo",rec.node.get("servers").get(1).get("url").asText());
- assertEquals("http://api.predic8.de/foo",rec.node.get("servers").get(2).get("url").asText());
- }
-
- @Test
- void rewriteRequestHostHeaderWithoutPort() throws URISyntaxException {
- OpenAPIRecord rec = records.get("servers-3-api-v1-0");
- get.setOriginalHostHeader("api.predic8.de");
- interceptor.rewriteOpenAPIaccordingToRequest(get, rec);
- JsonNode servers = rec.node.get("servers");
- assertEquals("http://api.predic8.de/foo", servers.get(0).get("url").textValue());
- assertEquals("http://api.predic8.de/foo", servers.get(1).get("url").textValue());
- assertEquals("http://api.predic8.de/foo", servers.get(2).get("url").textValue());
- }
-
- @Test
- void rewriteUrl() throws URISyntaxException {
- assertEquals("http://api.predic8.de/foo",interceptor.rewriteUrl(get,"http://localhost:3000/foo"));
- assertEquals("http://api.predic8.de/foo",interceptor.rewriteUrl(get,"http://localhost/foo"));
- }
}
\ No newline at end of file
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java
index e6371760d..579540d08 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/OpenAPIRecordTest.java
@@ -16,6 +16,11 @@
package com.predic8.membrane.core.openapi.serviceproxy;
+import com.predic8.membrane.core.*;
+import com.predic8.membrane.core.exchange.*;
+import com.predic8.membrane.core.http.*;
+import com.predic8.membrane.core.rules.*;
+import com.predic8.membrane.core.util.*;
import org.junit.jupiter.api.*;
import java.io.*;
@@ -25,16 +30,29 @@
class OpenAPIRecordTest {
+ Exchange get = new Exchange(null);
+
+ @BeforeEach
+ void setUp() {
+ Router router = new Router();
+ router.setUriFactory(new URIFactory());
+ router.setBaseLocation("");
+
+ get.setRequest(new Request.Builder().method("GET").build());
+ get.setRule(new NullRule());
+ get.setOriginalHostHeader("api.predic8.de:80");
+ }
+
@Test
void isVersion3() throws IOException {
- OpenAPIRecord rec = new OpenAPIRecord(null, getYAMLResource(this,"/openapi/specs/array.yml"));
+ OpenAPIRecord rec = new OpenAPIRecord(null, getYAMLResource(this,"/openapi/specs/array.yml"), null);
assertEquals("3.0.2", rec.version);
assertTrue(rec.isVersion3());
}
@Test
void isVersion2() throws IOException {
- OpenAPIRecord rec = new OpenAPIRecord(null, getYAMLResource(this,"/openapi/specs/fruitshop-swagger-2.0.json"));
+ OpenAPIRecord rec = new OpenAPIRecord(null, getYAMLResource(this,"/openapi/specs/fruitshop-swagger-2.0.json"), null);
assertEquals("2.0", rec.version);
assertTrue(rec.isVersion2());
}
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java
new file mode 100644
index 000000000..198be1010
--- /dev/null
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/RewriteTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2023 predic8 GmbH, www.predic8.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.predic8.membrane.core.openapi.serviceproxy;
+
+import com.fasterxml.jackson.databind.*;
+import com.predic8.membrane.core.*;
+import com.predic8.membrane.core.exchange.*;
+import com.predic8.membrane.core.http.*;
+import com.predic8.membrane.core.rules.*;
+import com.predic8.membrane.core.util.*;
+import org.jetbrains.annotations.*;
+import org.junit.jupiter.api.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.*;
+
+class RewriteTest {
+
+ Rewrite rewriteAll = new Rewrite();
+ Rewrite rewriteNothing = new Rewrite();
+
+ OpenAPISpec rewritesAllSpec;
+
+ Map records;
+
+ Exchange get = new Exchange(null);
+
+ @BeforeEach
+ void setUp() throws IOException {
+ rewriteAll.host = "predic8.de";
+ rewriteAll.port = 8080;
+ rewriteAll.protocol = "https";
+
+ Router router = new Router();
+ router.setUriFactory(new URIFactory());
+ router.setBaseLocation("");
+
+ OpenAPIRecordFactory openAPIRecordFactory = new OpenAPIRecordFactory(router);
+
+ rewritesAllSpec = getSpecRewriteAll();
+
+ OpenAPISpec spec = new OpenAPISpec();
+ spec.setDir("src/test/resources/openapi/specs");
+ records = openAPIRecordFactory.create(singletonList(spec));
+
+ get.setRequest(new Request.Builder().method("GET").build());
+ get.setRule(new NullRule());
+ get.setOriginalHostHeader("api.predic8.de:80");
+ }
+
+ @NotNull
+ private static OpenAPISpec getSpecRewriteAll() {
+ OpenAPISpec spec = new OpenAPISpec();
+ spec.setLocation("src/test/resources/openapi/specs/info-servers.yml");
+ Rewrite rewrite = new Rewrite();
+ rewrite.setProtocol("https");
+ rewrite.setPort(443);
+ rewrite.setHost("membrane-api.io");
+ spec.setRewrite(rewrite);
+ return spec;
+ }
+
+ @Test
+ void rewriteProtocol() {
+ assertEquals("https", rewriteAll.rewriteProtocol("http"));
+ assertEquals("http", rewriteNothing.rewriteProtocol("http"));
+ }
+
+ @Test
+ void rewriteHost() {
+ assertEquals("predic8.de", rewriteAll.rewriteHost("membrane-api.io"));
+ assertEquals("membrane-api.io", rewriteNothing.rewriteHost("membrane-api.io"));
+ }
+
+ @Test
+ void rewritePort() {
+ assertEquals("8080", rewriteAll.rewritePort("80"));
+ assertEquals("80", rewriteNothing.rewritePort("80"));
+ }
+
+ /**
+ * Test if rewritting changes the OpenAPI document.
+ * Secures currency.
+ */
+ @Test
+ void rewritingDoesNotChangeTheSpec() throws Exception {
+ OpenAPIRecord rec = records.get("servers-1-api-v1-0");
+ JsonNode servers = rec.node.get("servers");
+
+ String urlBefore = servers.get(0).get("url").asText();
+
+ rec.rewriteOpenAPI(get, new URIFactory());
+
+ JsonNode servers1 = rec.node.get("servers");
+ assertEquals(urlBefore, servers1.get(0).get("url").asText());
+ }
+
+ @Test
+ void rewriteSwagger2AccordingToRequestTest() throws Exception {
+ assertEquals("api.predic8.de:80", records.get("fruit-shop-api-swagger-2-v1-0-0").rewriteOpenAPI(get, new URIFactory()).get("host").asText());
+ }
+
+ @Test
+ void rewriteOpenAPIAccordingToRequestTest() throws Exception {
+ JsonNode servers = records.get("servers-1-api-v1-0").rewriteOpenAPI(get, new URIFactory()).get("servers");
+ assertEquals(1,servers.size());
+ assertEquals("http://api.predic8.de/base/v2", servers.get(0).get("url").asText());
+ assertEquals("Test System", records.get("servers-1-api-v1-0").node.get("servers").get(0).get("description").asText());
+ }
+
+ @Test
+ void rewriteOpenAPIAccordingToRequest3Servers() throws Exception {
+ OpenAPIRecord rec = records.get("servers-3-api-v1-0");
+ JsonNode servers = rec.rewriteOpenAPI(get, new URIFactory()).get("servers");
+ assertEquals(3,servers.size());
+ assertEquals("http://api.predic8.de/foo",servers.get(0).get("url").asText());
+ assertEquals("http://api.predic8.de/foo",servers.get(1).get("url").asText());
+ assertEquals("http://api.predic8.de/foo",servers.get(2).get("url").asText());
+ }
+
+ @Test
+ void rewriteOpenAPIAccordingToRewrite3Servers() throws Exception {
+ OpenAPIRecord rec = records.get("servers-3-api-v1-0");
+ rec.spec.rewrite.setHost("membrane-api.do");
+ rec.spec.rewrite.setPort(8443);
+ rec.spec.rewrite.setProtocol("https");
+ JsonNode servers = rec.rewriteOpenAPI(get, new URIFactory()).get("servers");
+ assertEquals(3,servers.size());
+ assertEquals("https://membrane-api.do:8443/foo",servers.get(0).get("url").asText());
+ assertEquals("https://membrane-api.do:8443/foo",servers.get(1).get("url").asText());
+ assertEquals("https://membrane-api.do:8443/foo",servers.get(2).get("url").asText());
+ }
+
+ @Test
+ void rewriteRequestHostHeaderWithoutPort() throws Exception {
+ OpenAPIRecord rec = records.get("servers-3-api-v1-0");
+ get.setOriginalHostHeader("api.predic8.de");
+ JsonNode servers = rec.rewriteOpenAPI(get, new URIFactory()).get("servers");
+ assertEquals("http://api.predic8.de/foo", servers.get(0).get("url").textValue());
+ assertEquals("http://api.predic8.de/foo", servers.get(1).get("url").textValue());
+ assertEquals("http://api.predic8.de/foo", servers.get(2).get("url").textValue());
+ }
+
+ @Test
+ void rewriteUrl() throws URISyntaxException {
+ assertEquals("http://api.predic8.de/foo", new Rewrite().rewriteUrl(get,"http://localhost:3000/foo", new URIFactory()));
+ assertEquals("http://api.predic8.de/foo", new Rewrite().rewriteUrl(get,"http://localhost/foo", new URIFactory()));
+ }
+
+ @Test
+ void rewriteOpenAPI3WithNoServers() throws Exception {
+ assertTrue(records.get("no-servers-v1-0").rewriteOpenAPI(get, new URIFactory()).get("servers").isEmpty());
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtentionTest.java b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtentionTest.java
index 43b930cb0..70e9ecd03 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtentionTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/serviceproxy/XMembraneExtentionTest.java
@@ -16,11 +16,9 @@
package com.predic8.membrane.core.openapi.serviceproxy;
-import com.fasterxml.jackson.databind.*;
import com.predic8.membrane.core.*;
import com.predic8.membrane.core.exchange.*;
import com.predic8.membrane.core.http.*;
-import io.swagger.v3.parser.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -38,7 +36,7 @@ public void setUp() throws IOException, ClassNotFoundException {
Router router = new Router();
router.setBaseLocation("");
OpenAPIRecordFactory factory = new OpenAPIRecordFactory(router);
- APIProxy.Spec spec = new APIProxy.Spec();
+ OpenAPISpec spec = new OpenAPISpec();
spec.setDir("src/test/resources/openapi/specs");
Map records = factory.create(Collections.singletonList(spec));
diff --git a/core/src/test/java/com/predic8/membrane/core/openapi/util/TestUtils.java b/core/src/test/java/com/predic8/membrane/core/openapi/util/TestUtils.java
index 57c8b98ee..e8c69718e 100644
--- a/core/src/test/java/com/predic8/membrane/core/openapi/util/TestUtils.java
+++ b/core/src/test/java/com/predic8/membrane/core/openapi/util/TestUtils.java
@@ -51,7 +51,7 @@ public static InputStream getResourceAsStream(Object obj, String fileName) {
return obj.getClass().getResourceAsStream(fileName);
}
- public static APIProxy createProxy(Router router, APIProxy.Spec spec) throws Exception {
+ public static APIProxy createProxy(Router router, OpenAPISpec spec) throws Exception {
APIProxy proxy = new APIProxy();
proxy.init(router);
proxy.setSpecs(singletonList(spec));
diff --git a/core/src/test/resources/openapi/specs/info-no-servers.yml b/core/src/test/resources/openapi/specs/info-no-servers.yml
new file mode 100644
index 000000000..8404c77ca
--- /dev/null
+++ b/core/src/test/resources/openapi/specs/info-no-servers.yml
@@ -0,0 +1,11 @@
+openapi: '3.0.2'
+info:
+ title: No Servers
+ version: '1.0'
+servers: []
+paths:
+ /foo:
+ get:
+ responses:
+ '200':
+ description: OK
|