From 1d553e7cf71d7d821f262d5773607d1ccaca661a Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Wed, 13 Jan 2021 12:44:57 +0200 Subject: [PATCH] Create better response when no GraphQL endpoint has been generated. Signed-off-by:Phillip Kruger --- .../SmallRyeGraphQLInitializedBuildItem.java | 17 +++++++++ .../deployment/SmallRyeGraphQLProcessor.java | 22 ++++++++--- .../SmallRyeGraphQLNoEndpointHandler.java | 21 +++++++++++ .../runtime/SmallRyeGraphQLRecorder.java | 37 ++++++++++++------- 4 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLInitializedBuildItem.java create mode 100644 extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLNoEndpointHandler.java diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLInitializedBuildItem.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLInitializedBuildItem.java new file mode 100644 index 0000000000000..d0000c5862aff --- /dev/null +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLInitializedBuildItem.java @@ -0,0 +1,17 @@ +package io.quarkus.smallrye.graphql.deployment; + +import io.quarkus.builder.item.SimpleBuildItem; +import io.quarkus.runtime.RuntimeValue; + +final class SmallRyeGraphQLInitializedBuildItem extends SimpleBuildItem { + + private final RuntimeValue initialized; + + public SmallRyeGraphQLInitializedBuildItem(RuntimeValue initialized) { + this.initialized = initialized; + } + + public RuntimeValue getInitialized() { + return initialized; + } +} \ No newline at end of file diff --git a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java index 28d3187b0d09d..ad3e990e5874a 100644 --- a/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java +++ b/extensions/smallrye-graphql/deployment/src/main/java/io/quarkus/smallrye/graphql/deployment/SmallRyeGraphQLProcessor.java @@ -43,6 +43,7 @@ import io.quarkus.deployment.util.ServiceUtil; import io.quarkus.deployment.util.WebJarUtil; import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.metrics.MetricsFactory; import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLRecorder; import io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLRuntimeConfig; @@ -51,7 +52,6 @@ import io.quarkus.vertx.http.deployment.RequireBodyHandlerBuildItem; import io.quarkus.vertx.http.deployment.RouteBuildItem; import io.quarkus.vertx.http.deployment.devmode.NotFoundPageDisplayableEndpointBuildItem; -import io.quarkus.vertx.http.runtime.HandlerType; import io.smallrye.graphql.cdi.config.ConfigKey; import io.smallrye.graphql.cdi.config.GraphQLConfig; import io.smallrye.graphql.cdi.producer.GraphQLProducer; @@ -145,6 +145,7 @@ void registerNativeImageResources(BuildProducer servic void buildExecutionService( BuildProducer reflectiveClassProducer, BuildProducer reflectiveHierarchyProducer, + BuildProducer graphQLInitializedProducer, SmallRyeGraphQLRecorder recorder, BeanContainerBuildItem beanContainer, CombinedIndexBuildItem combinedIndex, @@ -154,7 +155,8 @@ void buildExecutionService( Schema schema = SchemaBuilder.build(index, graphQLConfig.autoNameStrategy); - recorder.createExecutionService(beanContainer.getValue(), schema); + RuntimeValue initialized = recorder.createExecutionService(beanContainer.getValue(), schema); + graphQLInitializedProducer.produce(new SmallRyeGraphQLInitializedBuildItem(initialized)); // Make sure the complex object from the application can work in native mode reflectiveClassProducer.produce(new ReflectiveClassBuildItem(true, true, getSchemaJavaClasses(schema))); @@ -173,12 +175,18 @@ void requireBody(BuildProducer requireBodyHandlerPr @BuildStep void buildSchemaEndpoint( BuildProducer routeProducer, + SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem, SmallRyeGraphQLRecorder recorder, SmallRyeGraphQLConfig graphQLConfig) { - Handler schemaHandler = recorder.schemaHandler(); - routeProducer.produce( - new RouteBuildItem(graphQLConfig.rootPath + SCHEMA_PATH, schemaHandler, HandlerType.BLOCKING)); + Handler schemaHandler = recorder.schemaHandler(graphQLInitializedBuildItem.getInitialized()); + + routeProducer.produce(new RouteBuildItem.Builder() + .route(graphQLConfig.rootPath + SCHEMA_PATH) + .handler(schemaHandler) + .blockingRoute() + .build()); + } @Record(ExecutionTime.STATIC_INIT) @@ -186,6 +194,7 @@ void buildSchemaEndpoint( void buildExecutionEndpoint( BuildProducer routeProducer, BuildProducer notFoundPageDisplayableEndpointProducer, + SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem, SmallRyeGraphQLRecorder recorder, ShutdownContextBuildItem shutdownContext, LaunchModeBuildItem launchMode, @@ -217,7 +226,8 @@ void buildExecutionEndpoint( Boolean allowGet = ConfigProvider.getConfig().getOptionalValue(ConfigKey.ALLOW_GET, boolean.class).orElse(false); - Handler executionHandler = recorder.executionHandler(allowGet); + Handler executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(), + allowGet); routeProducer.produce(new RouteBuildItem.Builder() .route(graphQLConfig.rootPath) .handler(executionHandler) diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLNoEndpointHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLNoEndpointHandler.java new file mode 100644 index 0000000000000..3a28e2e68976f --- /dev/null +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLNoEndpointHandler.java @@ -0,0 +1,21 @@ +package io.quarkus.smallrye.graphql.runtime; + +import io.vertx.core.Handler; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; + +/** + * Handler that is used when no endpoint is available + */ +public class SmallRyeGraphQLNoEndpointHandler implements Handler { + private static final String CONTENT_TYPE = "text/plain; charset=UTF-8"; + private static final String MESSAGE = "GraphQL Schema not generated. Make sure you have a GraphQL Endpoint. Go to https://quarkus.io/guides/microprofile-graphql to learn how"; + + @Override + public void handle(RoutingContext event) { + HttpServerResponse response = event.response(); + response.headers().set(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE); + response.setStatusCode(404).end(MESSAGE); + } +} diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java index fb4160081b153..b87584a060108 100644 --- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java +++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java @@ -3,7 +3,9 @@ import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.CDI; +import graphql.schema.GraphQLSchema; import io.quarkus.arc.runtime.BeanContainer; +import io.quarkus.runtime.RuntimeValue; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; import io.quarkus.security.identity.CurrentIdentityAssociation; @@ -18,27 +20,36 @@ @Recorder public class SmallRyeGraphQLRecorder { - public void createExecutionService(BeanContainer beanContainer, Schema schema) { + public RuntimeValue createExecutionService(BeanContainer beanContainer, Schema schema) { GraphQLProducer graphQLProducer = beanContainer.instance(GraphQLProducer.class); GraphQLConfig graphQLConfig = beanContainer.instance(GraphQLConfig.class); - graphQLProducer.initialize(schema, graphQLConfig); + GraphQLSchema graphQLSchema = graphQLProducer.initialize(schema, graphQLConfig); + return new RuntimeValue<>(graphQLSchema != null); } - public Handler executionHandler(boolean allowGet) { - Instance identityAssociations = CDI.current() - .select(CurrentIdentityAssociation.class); - CurrentIdentityAssociation association; - if (identityAssociations.isResolvable()) { - association = identityAssociations.get(); + public Handler executionHandler(RuntimeValue initialized, boolean allowGet) { + if (initialized.getValue()) { + Instance identityAssociations = CDI.current() + .select(CurrentIdentityAssociation.class); + CurrentIdentityAssociation association; + if (identityAssociations.isResolvable()) { + association = identityAssociations.get(); + } else { + association = null; + } + CurrentVertxRequest currentVertxRequest = CDI.current().select(CurrentVertxRequest.class).get(); + return new SmallRyeGraphQLExecutionHandler(allowGet, association, currentVertxRequest); } else { - association = null; + return new SmallRyeGraphQLNoEndpointHandler(); } - CurrentVertxRequest currentVertxRequest = CDI.current().select(CurrentVertxRequest.class).get(); - return new SmallRyeGraphQLExecutionHandler(allowGet, association, currentVertxRequest); } - public Handler schemaHandler() { - return new SmallRyeGraphQLSchemaHandler(); + public Handler schemaHandler(RuntimeValue initialized) { + if (initialized.getValue()) { + return new SmallRyeGraphQLSchemaHandler(); + } else { + return new SmallRyeGraphQLNoEndpointHandler(); + } } public Handler uiHandler(String graphqlUiFinalDestination,