Skip to content

Commit

Permalink
Merge pull request #35767 from mskacelik/compression-SRGQL
Browse files Browse the repository at this point in the history
Added gzip compression feature for SmallRye-GraphQL, added tests
  • Loading branch information
jmartisk authored Sep 8, 2023
2 parents 6ebd9e6 + 110e460 commit 047ecb1
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import io.quarkus.vertx.http.deployment.webjar.WebJarBuildItem;
import io.quarkus.vertx.http.deployment.webjar.WebJarResourcesFilter;
import io.quarkus.vertx.http.deployment.webjar.WebJarResultsBuildItem;
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.smallrye.graphql.api.AdaptWith;
import io.smallrye.graphql.api.Deprecated;
import io.smallrye.graphql.api.Entry;
Expand Down Expand Up @@ -148,6 +149,8 @@ public class SmallRyeGraphQLProcessor {

private static final int GRAPHQL_WEBSOCKET_HANDLER_ORDER = -10000;

private static final String GRAPHQL_MEDIA_TYPE = "application/graphql+json";

@BuildStep
void feature(BuildProducer<FeatureBuildItem> featureProducer) {
featureProducer.produce(new FeatureBuildItem(Feature.SMALLRYE_GRAPHQL));
Expand Down Expand Up @@ -349,7 +352,8 @@ void buildExecutionEndpoint(
BodyHandlerBuildItem bodyHandlerBuildItem,
SmallRyeGraphQLConfig graphQLConfig,
BeanContainerBuildItem beanContainer,
BuildProducer<WebsocketSubProtocolsBuildItem> webSocketSubProtocols) {
BuildProducer<WebsocketSubProtocolsBuildItem> webSocketSubProtocols,
HttpBuildTimeConfig httpBuildTimeConfig) {

/*
* <em>Ugly Hack</em>
Expand Down Expand Up @@ -395,8 +399,11 @@ void buildExecutionEndpoint(
// Queries and Mutations
boolean allowGet = getBooleanConfigValue(ConfigKey.ALLOW_GET, false);
boolean allowQueryParametersOnPost = getBooleanConfigValue(ConfigKey.ALLOW_POST_WITH_QUERY_PARAMETERS, false);
boolean allowCompression = httpBuildTimeConfig.enableCompression && httpBuildTimeConfig.compressMediaTypes
.map(mediaTypes -> mediaTypes.contains(GRAPHQL_MEDIA_TYPE))
.orElse(false);
Handler<RoutingContext> executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(),
allowGet, allowQueryParametersOnPost, runBlocking);
allowGet, allowQueryParametersOnPost, runBlocking, allowCompression);

HttpRootPathBuildItem.Builder requestBuilder = httpRootPathBuildItem.routeBuilder()
.routeFunction(graphQLConfig.rootPath, recorder.routeFunction(bodyHandlerBuildItem.getHandler()))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.quarkus.smallrye.graphql.deployment;

import java.util.Arrays;

import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Query;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matchers;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class CompressionTest extends AbstractGraphQLTest {

private static final String PI = "3.141592653589793238462643383279502884197169399375105820";
private static final String TAU = "6.28";

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"))
.overrideConfigKey("quarkus.http.enable-compression", "true");

@Test
public void singleValidQueryCompressedResponseTest() {
String body = getPayload("{ validPiQuery }");
assertCompressed(body, PI);
}

@Test
public void multipleValidQueriesCompressedResponseTest() {
String body = getPayload("{ validPiQuery validTauQuery }");
assertCompressed(body, PI, TAU);
}

@Test
public void singleInvalidQueryCompressedResponseTest() {
String body = getPayload("{ invalidQuery }");
assertCompressed(body, "errors");
}

private void assertCompressed(String body, String... expectedOutput) {
org.hamcrest.Matcher messageMatcher = Arrays.stream(expectedOutput)
.map(CoreMatchers::containsString)
.reduce(Matchers.allOf(), (a, b) -> Matchers.allOf(a, b));

RestAssured.given()
.body(body)
.contentType(MEDIATYPE_JSON)
.post("/graphql")
.prettyPeek()
.then()
.assertThat()
.statusCode(200)
.header("Content-Encoding", "gzip")
.body(messageMatcher);
}

@GraphQLApi
public static class Schema {
@Query
public String validPiQuery() {
return PI;
}

@Query
public String validTauQuery() {
return TAU;
}

@Query
public String invalidQuery() {
throw new RuntimeException();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.quarkus.smallrye.graphql.runtime;

import io.vertx.core.Handler;
import io.vertx.core.http.HttpHeaders;
import io.vertx.ext.web.RoutingContext;

public class SmallRyeGraphQLCompressionHandler implements Handler<RoutingContext> {

private final Handler<RoutingContext> routeHandler;

public SmallRyeGraphQLCompressionHandler(Handler<RoutingContext> routeHandler) {
this.routeHandler = routeHandler;
}

@Override
public void handle(RoutingContext context) {
context.addHeadersEndHandler(new Handler<Void>() {
@Override
public void handle(Void event) {
context.response().headers().remove(HttpHeaders.CONTENT_ENCODING);
}
});
routeHandler.handle(context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,16 @@ public RuntimeValue<Boolean> createExecutionService(BeanContainer beanContainer,
}

public Handler<RoutingContext> executionHandler(RuntimeValue<Boolean> initialized, boolean allowGet,
boolean allowPostWithQueryParameters, boolean runBlocking) {
boolean allowPostWithQueryParameters, boolean runBlocking, boolean allowCompression) {
if (initialized.getValue()) {
return new SmallRyeGraphQLExecutionHandler(allowGet, allowPostWithQueryParameters, runBlocking,
Handler<RoutingContext> handler = new SmallRyeGraphQLExecutionHandler(allowGet,
allowPostWithQueryParameters, runBlocking,
getCurrentIdentityAssociation(),
Arc.container().instance(CurrentVertxRequest.class).get());
if (allowCompression) {
return new SmallRyeGraphQLCompressionHandler(handler);
}
return handler;
} else {
return new SmallRyeGraphQLNoEndpointHandler();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class HttpBuildTimeConfig {
* List of media types for which the compression should be enabled automatically, unless declared explicitly via
* {@link Compressed} or {@link Uncompressed}.
*/
@ConfigItem(defaultValue = "text/html,text/plain,text/xml,text/css,text/javascript,application/javascript")
@ConfigItem(defaultValue = "text/html,text/plain,text/xml,text/css,text/javascript,application/javascript,application/graphql+json")
public Optional<List<String>> compressMediaTypes;

/**
Expand Down

0 comments on commit 047ecb1

Please sign in to comment.