Skip to content

Commit

Permalink
Merge pull request #25194 from phillip-kruger/gql-nb
Browse files Browse the repository at this point in the history
GraphQL Non blocking support
  • Loading branch information
gsmet authored May 5, 2022
2 parents 0bfe9a2 + 9f7a2cd commit 5427907
Show file tree
Hide file tree
Showing 32 changed files with 1,785 additions and 89 deletions.
2 changes: 1 addition & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<smallrye-health.version>3.2.1</smallrye-health.version>
<smallrye-metrics.version>3.0.4</smallrye-metrics.version>
<smallrye-open-api.version>2.1.22</smallrye-open-api.version>
<smallrye-graphql.version>1.4.5</smallrye-graphql.version>
<smallrye-graphql.version>1.5.0</smallrye-graphql.version>
<smallrye-opentracing.version>2.1.0</smallrye-opentracing.version>
<smallrye-fault-tolerance.version>5.4.0</smallrye-fault-tolerance.version>
<smallrye-jwt.version>3.4.0</smallrye-jwt.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,15 @@ void registerAdditionalBeans(HibernateValidatorRecorder hibernateValidatorRecord
// The CDI interceptor which will validate the methods annotated with @MethodValidated
additionalBeans.produce(new AdditionalBeanBuildItem(MethodValidationInterceptor.class));

additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.LocaleResolversWrapper"));

if (capabilities.isPresent(Capability.RESTEASY)) {
// The CDI interceptor which will validate the methods annotated with @JaxrsEndPointValidated
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.jaxrs.JaxrsEndPointValidationInterceptor"));
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.LocaleResolversWrapper"));
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.ResteasyContextLocaleResolver"));
"io.quarkus.hibernate.validator.runtime.locale.ResteasyClassicLocaleResolver"));
syntheticBeanBuildItems.produce(SyntheticBeanBuildItem.configure(ResteasyConfigSupport.class)
.scope(Singleton.class)
.unremovable()
Expand All @@ -160,15 +161,7 @@ void registerAdditionalBeans(HibernateValidatorRecorder hibernateValidatorRecord
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.jaxrs.ResteasyReactiveEndPointValidationInterceptor"));
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.LocaleResolversWrapper"));
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.VertxLocaleResolver"));
}
if (capabilities.isPresent(Capability.SMALLRYE_GRAPHQL)) {
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.LocaleResolversWrapper"));
additionalBeans.produce(new AdditionalBeanBuildItem(
"io.quarkus.hibernate.validator.runtime.locale.VertxLocaleResolver"));
"io.quarkus.hibernate.validator.runtime.locale.ResteasyReactiveLocaleResolver"));
}

// A constraint validator with an injection point but no scope is added as @Dependent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@
public class LocaleResolversWrapper implements LocaleResolver {

@Inject
Instance<AbstractLocaleResolver> resolvers;
Instance<LocaleResolver> resolvers;

@Override
public Locale resolve(LocaleResolverContext context) {
for (AbstractLocaleResolver resolver : resolvers) {
Locale locale = resolver.resolve(context);
if (locale != null) {
return locale;
for (LocaleResolver resolver : resolvers) {
if (!resolver.equals(this)) {
Locale locale = resolver.resolve(context);
if (locale != null) {
return locale;
}
}
}
return context.getDefaultLocale();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.jboss.resteasy.core.ResteasyContext;

@Singleton
public class ResteasyContextLocaleResolver extends AbstractLocaleResolver {
public class ResteasyClassicLocaleResolver extends AbstractLocaleResolver {

@Override
protected Map<String, List<String>> getHeaders() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* Currently used for handling GraphQL requests.
*/
@Singleton
public class VertxLocaleResolver extends AbstractLocaleResolver {
public class ResteasyReactiveLocaleResolver extends AbstractLocaleResolver {

@Inject
CurrentVertxRequest currentVertxRequest;
Expand Down
4 changes: 4 additions & 0 deletions extensions/smallrye-graphql-client/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-stork-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-graphql-client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
@GraphQLApi
public class TestingGraphQLApi {

@Inject
CurrentVertxRequest request;

@Query
public List<Person> people() {
Person person1 = new Person();
Expand All @@ -25,9 +28,6 @@ public List<Person> people() {
return List.of(person1, person2);
}

@Inject
CurrentVertxRequest request;

/**
* Returns the value of the HTTP header denoted by 'key'.
*/
Expand Down
5 changes: 4 additions & 1 deletion extensions/smallrye-graphql-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-stork</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-graphql-client-implementation-vertx</artifactId>
Expand Down
12 changes: 7 additions & 5 deletions extensions/smallrye-graphql/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
<artifactId>quarkus-smallrye-context-propagation-deployment</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator-deployment</artifactId>
<optional>true</optional>
<scope>provided</scope>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
Expand Down Expand Up @@ -94,11 +101,6 @@
<artifactId>opentracing-mock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-validator-deployment</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import io.quarkus.runtime.configuration.ConfigurationException;
import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLConfig;
import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLConfigMapping;
import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLLocaleResolver;
import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLRecorder;
import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLRuntimeConfig;
import io.quarkus.vertx.http.deployment.BodyHandlerBuildItem;
Expand All @@ -65,7 +66,6 @@
import io.smallrye.graphql.cdi.config.ConfigKey;
import io.smallrye.graphql.cdi.config.MicroProfileConfig;
import io.smallrye.graphql.cdi.producer.GraphQLProducer;
import io.smallrye.graphql.cdi.producer.SmallRyeContextAccessorProxy;
import io.smallrye.graphql.schema.Annotations;
import io.smallrye.graphql.schema.SchemaBuilder;
import io.smallrye.graphql.schema.model.Argument;
Expand Down Expand Up @@ -143,11 +143,16 @@ void additionalBeanDefiningAnnotation(BuildProducer<BeanDefiningAnnotationBuildI
}

@BuildStep
void additionalBean(BuildProducer<AdditionalBeanBuildItem> additionalBeanProducer) {
void additionalBean(Capabilities capabilities, BuildProducer<AdditionalBeanBuildItem> additionalBeanProducer) {

additionalBeanProducer.produce(AdditionalBeanBuildItem.builder()
.addBeanClass(GraphQLProducer.class)
.addBeanClass(SmallRyeContextAccessorProxy.class)
.setUnremovable().build());
if (capabilities.isPresent(Capability.HIBERNATE_VALIDATOR)) {
additionalBeanProducer.produce(AdditionalBeanBuildItem.builder()
.addBeanClass(SmallRyeGraphQLLocaleResolver.class)
.setUnremovable().build());
}
}

@BuildStep
Expand Down Expand Up @@ -249,7 +254,6 @@ void buildSchemaEndpoint(
.nestedRoute(graphQLConfig.rootPath, SCHEMA_PATH)
.handler(schemaHandler)
.displayOnNotFoundPage("MicroProfile GraphQL Schema")
.blockingRoute()
.build());

}
Expand Down Expand Up @@ -286,10 +290,10 @@ void buildExecutionEndpoint(
Handler<RoutingContext> graphqlOverWebsocketHandler = recorder
.graphqlOverWebsocketHandler(beanContainer.getValue(), graphQLInitializedBuildItem.getInitialized());

routeProducer.produce(httpRootPathBuildItem.routeBuilder()
HttpRootPathBuildItem.Builder subscriptionsBuilder = httpRootPathBuildItem.routeBuilder()
.orderedRoute(graphQLConfig.rootPath, Integer.MIN_VALUE)
.handler(graphqlOverWebsocketHandler)
.build());
.handler(graphqlOverWebsocketHandler);
routeProducer.produce(subscriptionsBuilder.build());

// WebSocket subprotocols
graphQLConfig.websocketSubprotocols.ifPresentOrElse(subprotocols -> {
Expand All @@ -308,18 +312,31 @@ void buildExecutionEndpoint(
});

// Queries and Mutations
boolean runBlocking = shouldRunBlockingRoute(graphQLConfig);
boolean allowGet = getBooleanConfigValue(ConfigKey.ALLOW_GET, false);
boolean allowQueryParametersOnPost = getBooleanConfigValue(ConfigKey.ALLOW_POST_WITH_QUERY_PARAMETERS, false);
Handler<RoutingContext> executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(),
allowGet, allowQueryParametersOnPost);
routeProducer.produce(httpRootPathBuildItem.routeBuilder()
allowGet, allowQueryParametersOnPost, runBlocking);

HttpRootPathBuildItem.Builder requestBuilder = httpRootPathBuildItem.routeBuilder()
.routeFunction(graphQLConfig.rootPath, recorder.routeFunction(bodyHandlerBuildItem.getHandler()))
.handler(executionHandler)
.routeConfigKey("quarkus.smallrye-graphql.root-path")
.displayOnNotFoundPage("MicroProfile GraphQL Endpoint")
.blockingRoute()
.build());
.displayOnNotFoundPage("MicroProfile GraphQL Endpoint");

if (runBlocking) {
requestBuilder = requestBuilder.blockingRoute();
}

routeProducer.produce(requestBuilder.build());

}

private boolean shouldRunBlockingRoute(SmallRyeGraphQLConfig graphQLConfig) {
if (graphQLConfig.nonBlockingEnabled.isPresent()) {
return !graphQLConfig.nonBlockingEnabled.get();
}
return false;
}

private boolean getBooleanConfigValue(String smallryeKey, boolean defaultValue) {
Expand All @@ -338,7 +355,7 @@ private String[] getSchemaJavaClasses(Schema schema) {
classes.addAll(getInputClassNames(schema.getInputs().values()));
classes.addAll(getInterfaceClassNames(schema.getInterfaces().values()));

return classes.toArray(new String[] {});
return classes.toArray(String[]::new);
}

private Class[] getGraphQLJavaClasses() {
Expand All @@ -361,7 +378,7 @@ private Class[] getGraphQLJavaClasses() {
classes.add(graphql.schema.GraphQLTypeReference.class);
classes.add(List.class);
classes.add(Collection.class);
return classes.toArray(new Class[] {});
return classes.toArray(Class[]::new);
}

private Set<String> getOperationClassNames(Set<Operation> operations) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.quarkus.smallrye.graphql.deployment;

import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Query;
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;
import io.smallrye.common.annotation.NonBlocking;

public class ErrorTest extends AbstractGraphQLTest {

@RegisterExtension
static QuarkusUnitTest test = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(ErrorApi.class, Foo.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"));

@Test
public void testNonBlockingError() {
String query = getPayload("{ foo { message} }");
RestAssured.given()
.body(query)
.contentType(MEDIATYPE_JSON)
.post("/graphql/")
.then()
.assertThat()
.statusCode(500);
}

@Test
public void testBlockingError() {
String query = getPayload("{ blockingFoo { message} }");
RestAssured.given()
.body(query)
.contentType(MEDIATYPE_JSON)
.post("/graphql/")
.then()
.log().everything()
.assertThat()
.statusCode(500);
}

public static class Foo {

private String message;

public Foo(String foo) {
this.message = foo;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

}

@GraphQLApi
@ApplicationScoped
public static class ErrorApi {

@Query
@NonBlocking
public Foo foo() {
throw new OutOfMemoryError("a SuperHero has used all the memory");
}

@Query
public Foo blockingFoo() {
throw new OutOfMemoryError("a SuperHero has used all the memory");
}

}

}
Loading

0 comments on commit 5427907

Please sign in to comment.