Skip to content

Commit

Permalink
added dynamic rewriter for openApiDocs (membrane#1169)
Browse files Browse the repository at this point in the history
* fixed issue membrane#1163

* added javadoc comment and Test

* refactor: split test cases

* fixed rewriting

* fixed rewriting

* Add unit tests for APIProxyKey

* Add unit tests for APIProxyKey

* Add unit tests for APIProxyKey

* Add unit tests for APIProxyKey

* Rollback proxies.xml

---------

Co-authored-by: Torben Burchgart <[email protected]>
Co-authored-by: t-burch <[email protected]>
  • Loading branch information
3 people authored Jul 5, 2024
1 parent db08029 commit 1ba4f17
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.validation.constraints.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -60,6 +63,7 @@ public Outcome handleRequest(Exchange exc) throws Exception {
public Map<String, OpenAPIRecord> initializeRuleApiSpecs() {
return router.getRuleManager().getRules().stream()
.filter(this::hasOpenAPIInterceptor)
.peek(this::setSpecRewrites)
.flatMap(this::getRecordEntryStreamOrEmpty)
.collect(Collectors.toMap(
Map.Entry::getKey,
Expand All @@ -69,6 +73,24 @@ public Map<String, OpenAPIRecord> initializeRuleApiSpecs() {
));
}

protected void setSpecRewrites(Rule rule) {
var key = rule.getKey();
//noinspection OptionalGetWithoutIsPresent
getOpenAPIInterceptor(rule).get().getApiProxy().getSpecs().forEach(spec -> {
if (spec.getRewrite() != null) {
setIfNull(spec.getRewrite(), Rewrite::getPort, Rewrite::setPort, key.getPort());
setIfNull(spec.getRewrite(), Rewrite::getHost, Rewrite::setHost, key.getHost());
setIfNull(spec.getRewrite(), Rewrite::getBasePath, Rewrite::setBasePath, key.getPath());
} else {
spec.setRewrite(new Rewrite() {{
setHost(key.getHost());
setPort(key.getPort());
setBasePath(key.getPath());
}});
}
});
}

private Stream<Map.Entry<String, OpenAPIRecord>> getRecordEntryStreamOrEmpty(Rule rule) {
return getOpenAPIInterceptor(rule)
.map(ApiDocsInterceptor::getRecordEntryStream)
Expand All @@ -84,7 +106,7 @@ private boolean hasOpenAPIInterceptor(Rule rule) {
return rule.getInterceptors().stream().anyMatch(ic -> ic instanceof OpenAPIInterceptor);
}

Optional<OpenAPIInterceptor> getOpenAPIInterceptor(Rule rule) {
static Optional<OpenAPIInterceptor> getOpenAPIInterceptor(Rule rule) {
return rule.getInterceptors().stream()
.filter(ic -> ic instanceof OpenAPIInterceptor)
.map(ic -> (OpenAPIInterceptor) ic) // Previous line checks type, so cast should be fine
Expand Down Expand Up @@ -126,4 +148,11 @@ public String getLongDescription() {

return sb.toString();
}
}

public static <T, U> void setIfNull(T rewrite, Function<T, U> getter, BiConsumer<T, U> setter, U defaultValue) {
if(getter.apply(rewrite) != null) return;
if(!defaultValue.equals("*")) {
setter.accept(rewrite, defaultValue);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public String rewritePort(String port) {
}


public int getPort() {
public Integer getPort() {
return port;
}

Expand Down
54 changes: 30 additions & 24 deletions core/src/main/java/com/predic8/membrane/core/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,26 @@

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.predic8.membrane.core.http.*;
import jakarta.mail.internet.*;
import org.slf4j.*;

import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

import static com.predic8.membrane.core.http.MimeType.*;
import com.predic8.membrane.core.http.Response;
import jakarta.mail.internet.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.predic8.membrane.core.http.MimeType.APPLICATION_JSON;

public class Util {

Expand Down Expand Up @@ -59,16 +66,16 @@ public static HashMap<String, String> parseSimpleJSONResponse(Response g) throws
String name = null;
while (jp.nextToken() != null) {
switch (jp.getCurrentToken()) {
case FIELD_NAME:
name = jp.getCurrentName();
break;
case VALUE_STRING:
values.put(name, jp.getText());
break;
case VALUE_NUMBER_INT:
values.put(name, "" + jp.getLongValue());
default:
break;
case FIELD_NAME:
name = jp.getCurrentName();
break;
case VALUE_STRING:
values.put(name, jp.getText());
break;
case VALUE_NUMBER_INT:
values.put(name, "" + jp.getLongValue());
default:
break;
}
}
}
Expand Down Expand Up @@ -109,7 +116,6 @@ public static ExecutorService createNewThreadPool() {
}

/**
*
* @param string String that might be separated by comma e.g. "a,b,c"
* @return mutable list
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@

import static com.predic8.membrane.core.http.MimeType.APPLICATION_PROBLEM_JSON;
import static com.predic8.membrane.core.interceptor.Outcome.RETURN;
import static com.predic8.membrane.core.openapi.serviceproxy.ApiDocsInterceptor.getOpenAPIInterceptor;
import static com.predic8.membrane.core.openapi.util.TestUtils.createProxy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

@SuppressWarnings("OptionalGetWithoutIsPresent")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ApiDocsInterceptorTest {

Expand Down Expand Up @@ -69,35 +70,35 @@ public void setUp() throws Exception {
}

@AfterEach
public void tearDown() {
void tearDown() {
router.stop();
}

@Test
public void initTest() throws Exception {
void initTest() throws Exception {
assertEquals(RETURN, interceptor.handleRequest(exc));
}

@Test
public void getOpenApiInterceptorTest() {
assertEquals("OpenAPI", interceptor.getOpenAPIInterceptor(rule).get().getDisplayName());
assertEquals(Optional.empty(), interceptor.getOpenAPIInterceptor(new APIProxy()));
void getOpenApiInterceptorTest() {
assertEquals("OpenAPI", getOpenAPIInterceptor(rule).get().getDisplayName());
assertEquals(Optional.empty(), getOpenAPIInterceptor(new APIProxy()));
}

@Test
public void initializeRuleApiSpecsTest() {
assertEquals(interceptor.getOpenAPIInterceptor(rule).get().getApiProxy().apiRecords, interceptor.initializeRuleApiSpecs());
void initializeRuleApiSpecsTest() {
assertEquals(getOpenAPIInterceptor(rule).get().getApiProxy().apiRecords, interceptor.initializeRuleApiSpecs());
}

@Test
public void initializeEmptyRuleApiSpecsTest() throws Exception {
void initializeEmptyRuleApiSpecsTest() throws Exception {
ApiDocsInterceptor adi = new ApiDocsInterceptor();
adi.init(new Router());
assertEquals(new HashMap<>(), adi.initializeRuleApiSpecs());
}

@Test
public void getHTMLOverview() throws Exception {
void getHTMLOverview() throws Exception {
exc.getRequest().setUri("/api-docs");
Header header = new Header();
header.setAccept("html");
Expand All @@ -107,20 +108,46 @@ public void getHTMLOverview() throws Exception {
}

@Test
public void getSwaggerUI() throws Exception {
void getSwaggerUI() throws Exception {
exc.getRequest().setUri("/api-docs/ui/fruit-shop-api-v2-0-0");
assertEquals(RETURN, interceptor.handleRequest(exc));
assertTrue(exc.getResponse().getBodyAsStringDecoded().contains("Swagger"));
}

@Test
public void getSwaggerUIWrongId() throws Exception {
void getSwaggerUIWrongId() throws Exception {
exc.getRequest().setUri("/api-docs/wrong-id");
assertEquals(RETURN, interceptor.handleRequest(exc));
assertEquals(404, exc.getResponse().getStatusCode());
checkHasValidProblemJSON(exc);
}

@Test
void noRewriterSetSpecRewritesTest() {
interceptor.setSpecRewrites(rule);
Rewrite rewrite = getRewrite();
assertEquals(2000, rewrite.getPort());
assertEquals("", rewrite.getHost());
}

@Test
void rewriterSetSpecRewritesTest() {
getOpenAPIInterceptor(rule).get().getApiProxy().getSpecs().get(0).setRewrite(new Rewrite() {{
setPort(3000);
setHost("localhost");
setBasePath("/foo");
}});
interceptor.setSpecRewrites(rule);
Rewrite rewrite = getRewrite();
assertEquals(3000, rewrite.getPort());
assertEquals("/foo", rewrite.getBasePath());
assertEquals("localhost", rewrite.getHost());
}

private Rewrite getRewrite() {
return getOpenAPIInterceptor(rule).get().getApiProxy().getSpecs().get(0).getRewrite();
}

private void checkHasValidProblemJSON(Exchange exc) throws IOException {
assertEquals(APPLICATION_PROBLEM_JSON, exc.getResponse().getHeader().getContentType());
assertTrue(exc.getResponse().isJSON());
Expand All @@ -130,4 +157,37 @@ private void checkHasValidProblemJSON(Exchange exc) throws IOException {
assertTrue(json.has("title"));
assertTrue(json.has("type"));
}

@Test
void testSetPortIfNull() {
Rewrite rewrite = new Rewrite();

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getPort, Rewrite::setPort, 8080);
assertEquals(8080, rewrite.getPort());

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getPort, Rewrite::setPort, 9090);
assertEquals(8080, rewrite.getPort());
}

@Test
void testSetHostIfNull() {
Rewrite rewrite = new Rewrite();

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getHost, Rewrite::setHost, "localhost");
assertEquals("localhost", rewrite.getHost());

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getHost, Rewrite::setHost, "127.0.0.1");
assertEquals("localhost", rewrite.getHost());
}

@Test
void testSetBasePathIfNull() {
Rewrite rewrite = new Rewrite();

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getBasePath, Rewrite::setBasePath, "/api");
assertEquals("/api", rewrite.getBasePath());

ApiDocsInterceptor.setIfNull(rewrite, Rewrite::getBasePath, Rewrite::setBasePath, "/new-api");
assertEquals("/api", rewrite.getBasePath());
}
}

0 comments on commit 1ba4f17

Please sign in to comment.