Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create better response when no GraphQL endpoint has been generated #14278

Merged
merged 1 commit into from
Jan 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<Boolean> initialized;

public SmallRyeGraphQLInitializedBuildItem(RuntimeValue<Boolean> initialized) {
this.initialized = initialized;
}

public RuntimeValue<Boolean> getInitialized() {
return initialized;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -145,6 +145,7 @@ void registerNativeImageResources(BuildProducer<ServiceProviderBuildItem> servic
void buildExecutionService(
BuildProducer<ReflectiveClassBuildItem> reflectiveClassProducer,
BuildProducer<ReflectiveHierarchyBuildItem> reflectiveHierarchyProducer,
BuildProducer<SmallRyeGraphQLInitializedBuildItem> graphQLInitializedProducer,
SmallRyeGraphQLRecorder recorder,
BeanContainerBuildItem beanContainer,
CombinedIndexBuildItem combinedIndex,
Expand All @@ -154,7 +155,8 @@ void buildExecutionService(

Schema schema = SchemaBuilder.build(index, graphQLConfig.autoNameStrategy);

recorder.createExecutionService(beanContainer.getValue(), schema);
RuntimeValue<Boolean> 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)));
Expand All @@ -173,19 +175,26 @@ void requireBody(BuildProducer<RequireBodyHandlerBuildItem> requireBodyHandlerPr
@BuildStep
void buildSchemaEndpoint(
BuildProducer<RouteBuildItem> routeProducer,
SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem,
SmallRyeGraphQLRecorder recorder,
SmallRyeGraphQLConfig graphQLConfig) {

Handler<RoutingContext> schemaHandler = recorder.schemaHandler();
routeProducer.produce(
new RouteBuildItem(graphQLConfig.rootPath + SCHEMA_PATH, schemaHandler, HandlerType.BLOCKING));
Handler<RoutingContext> schemaHandler = recorder.schemaHandler(graphQLInitializedBuildItem.getInitialized());

routeProducer.produce(new RouteBuildItem.Builder()
.route(graphQLConfig.rootPath + SCHEMA_PATH)
.handler(schemaHandler)
.blockingRoute()
.build());

}

@Record(ExecutionTime.STATIC_INIT)
@BuildStep
void buildExecutionEndpoint(
BuildProducer<RouteBuildItem> routeProducer,
BuildProducer<NotFoundPageDisplayableEndpointBuildItem> notFoundPageDisplayableEndpointProducer,
SmallRyeGraphQLInitializedBuildItem graphQLInitializedBuildItem,
SmallRyeGraphQLRecorder recorder,
ShutdownContextBuildItem shutdownContext,
LaunchModeBuildItem launchMode,
Expand Down Expand Up @@ -217,7 +226,8 @@ void buildExecutionEndpoint(

Boolean allowGet = ConfigProvider.getConfig().getOptionalValue(ConfigKey.ALLOW_GET, boolean.class).orElse(false);

Handler<RoutingContext> executionHandler = recorder.executionHandler(allowGet);
Handler<RoutingContext> executionHandler = recorder.executionHandler(graphQLInitializedBuildItem.getInitialized(),
allowGet);
routeProducer.produce(new RouteBuildItem.Builder()
.route(graphQLConfig.rootPath)
.handler(executionHandler)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<RoutingContext> {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -18,27 +20,36 @@
@Recorder
public class SmallRyeGraphQLRecorder {

public void createExecutionService(BeanContainer beanContainer, Schema schema) {
public RuntimeValue<Boolean> 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<RoutingContext> executionHandler(boolean allowGet) {
Instance<CurrentIdentityAssociation> identityAssociations = CDI.current()
.select(CurrentIdentityAssociation.class);
CurrentIdentityAssociation association;
if (identityAssociations.isResolvable()) {
association = identityAssociations.get();
public Handler<RoutingContext> executionHandler(RuntimeValue<Boolean> initialized, boolean allowGet) {
if (initialized.getValue()) {
Instance<CurrentIdentityAssociation> 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<RoutingContext> schemaHandler() {
return new SmallRyeGraphQLSchemaHandler();
public Handler<RoutingContext> schemaHandler(RuntimeValue<Boolean> initialized) {
if (initialized.getValue()) {
return new SmallRyeGraphQLSchemaHandler();
} else {
return new SmallRyeGraphQLNoEndpointHandler();
}
}

public Handler<RoutingContext> uiHandler(String graphqlUiFinalDestination,
Expand Down