From f2cf46989b77398ae06ece14d93bc27ebe4ba8cf Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Mon, 14 Sep 2020 07:28:49 +1000 Subject: [PATCH] Refactor webmvc to use the new Handler --- spring-graphql-common/build.gradle | 2 +- spring-graphql-webmvc/build.gradle | 1 + .../servlet/GraphQLInvocationData.java | 31 ---------- .../servlet/components/GraphQLController.java | 56 ++++++++++++++++--- .../components/GraphQLRequestHandler.java | 55 ------------------ ...dy.java => GraphQLServletRequestBody.java} | 2 +- 6 files changed, 52 insertions(+), 95 deletions(-) delete mode 100644 spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/GraphQLInvocationData.java delete mode 100644 spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestHandler.java rename spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/{GraphQLRequestBody.java => GraphQLServletRequestBody.java} (94%) diff --git a/spring-graphql-common/build.gradle b/spring-graphql-common/build.gradle index bfa44d94..ae7950d1 100644 --- a/spring-graphql-common/build.gradle +++ b/spring-graphql-common/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'java-library' dependencies { implementation "org.springframework:spring-web:$springVersion" - implementation 'io.projectreactor:reactor-core:3.3.8.RELEASE' + api 'io.projectreactor:reactor-core:3.3.8.RELEASE' api "com.graphql-java:graphql-java:$graphqlJavaVersion" testImplementation("org.assertj:assertj-core:$assertJVersion") diff --git a/spring-graphql-webmvc/build.gradle b/spring-graphql-webmvc/build.gradle index bb7f9f96..9343a0b3 100644 --- a/spring-graphql-webmvc/build.gradle +++ b/spring-graphql-webmvc/build.gradle @@ -7,6 +7,7 @@ dependencies { implementation "org.springframework:spring-context:$springVersion" implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" api "com.graphql-java:graphql-java:$graphqlJavaVersion" + implementation project(':spring-graphql-common') implementation group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1' testImplementation("org.assertj:assertj-core:$assertJVersion") diff --git a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/GraphQLInvocationData.java b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/GraphQLInvocationData.java deleted file mode 100644 index dab716cd..00000000 --- a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/GraphQLInvocationData.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.springframework.graphql.servlet; - -import graphql.Assert; - -import java.util.Collections; -import java.util.Map; - -public class GraphQLInvocationData { - - private final String query; - private final String operationName; - private final Map variables; - - public GraphQLInvocationData(String query, String operationName, Map variables) { - this.query = Assert.assertNotNull(query, () -> "query must be provided"); - this.operationName = operationName; - this.variables = variables != null ? variables : Collections.emptyMap(); - } - - public String getQuery() { - return query; - } - - public String getOperationName() { - return operationName; - } - - public Map getVariables() { - return variables; - } -} diff --git a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLController.java b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLController.java index 7baae1c8..c3c8bdfb 100644 --- a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLController.java +++ b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLController.java @@ -1,18 +1,27 @@ package org.springframework.graphql.servlet.components; +import graphql.GraphQL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.graphql.servlet.GraphQLInvocationData; +import org.springframework.graphql.DefaultGraphQLInterceptor; +import org.springframework.graphql.GraphQLHandler; +import org.springframework.graphql.GraphQLInterceptor; +import org.springframework.graphql.GraphQLRequestBody; import org.springframework.http.MediaType; import org.springframework.web.servlet.function.RequestPredicates; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; +import reactor.core.publisher.Mono; +import javax.annotation.PostConstruct; import javax.servlet.ServletException; import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import static org.springframework.web.servlet.function.RouterFunctions.route; @@ -20,7 +29,20 @@ import static org.springframework.web.servlet.function.RouterFunctions.route; public class GraphQLController { @Autowired - GraphQLRequestHandler graphQLRequestHandler; + GraphQL graphQL; + + GraphQLHandler graphQLHandler; + + @Autowired(required = false) + GraphQLInterceptor graphQLInterceptor; + + + @PostConstruct + public void init() { + GraphQLInterceptor interceptor = graphQLInterceptor == null ? new DefaultGraphQLInterceptor() : graphQLInterceptor; + this.graphQLHandler = new GraphQLHandler(graphQL, interceptor); + } + @Bean public RouterFunction routerFunction() { @@ -33,9 +55,9 @@ public class GraphQLController { } private ServerResponse graphqlPOST(ServerRequest serverRequest) { - GraphQLRequestBody body = null; + GraphQLServletRequestBody body = null; try { - body = serverRequest.body(GraphQLRequestBody.class); + body = serverRequest.body(GraphQLServletRequestBody.class); } catch (ServletException | IOException e) { e.printStackTrace(); } @@ -43,9 +65,29 @@ public class GraphQLController { if (query == null) { query = ""; } - GraphQLInvocationData invocationData = new GraphQLInvocationData(query, body.getOperationName(), body.getVariables()); - Object resultBody = graphQLRequestHandler.invoke(invocationData, serverRequest.headers()); - return ServerResponse.ok().body(resultBody); + Map variables = body.getVariables(); + if (variables == null) { + variables = Collections.emptyMap(); + } + + GraphQLRequestBody graphQLRequestBody = new GraphQLRequestBody(query, body.getOperationName(), variables); + + Mono> responseRawMono = graphQLHandler.graphqlPOST(graphQLRequestBody, serverRequest.headers().asHttpHeaders()) + .map(graphQLResponseBody -> { + //TODO: this should be handled better: + // we don't want to serialize `null` values for `errors` and `extensions` + // this is why we convert it to a Map here + Map responseBodyRaw = new LinkedHashMap<>(); + responseBodyRaw.put("data", graphQLResponseBody.getData()); + if (graphQLResponseBody.getErrors() != null) { + responseBodyRaw.put("errors", graphQLResponseBody.getErrors()); + } + if (graphQLResponseBody.getExtensions() != null) { + responseBodyRaw.put("extensions", graphQLResponseBody.getExtensions()); + } + return responseBodyRaw; + }); + return ServerResponse.ok().body(responseRawMono); } } diff --git a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestHandler.java b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestHandler.java deleted file mode 100644 index 2eb29f44..00000000 --- a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.springframework.graphql.servlet.components; - -import graphql.ExecutionInput; -import graphql.ExecutionResult; -import graphql.GraphQL; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.graphql.servlet.GraphQLInvocationData; -import org.springframework.stereotype.Component; -import org.springframework.util.Assert; -import org.springframework.web.servlet.function.ServerRequest; - -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -@Component -public class GraphQLRequestHandler { - - @Autowired - private GraphQL graphQL; - - - public Object invoke(GraphQLInvocationData invocationData, - ServerRequest.Headers headers) { - Assert.notNull(graphQL, "graphQL is not set"); - ExecutionInput executionInput = ExecutionInput.newExecutionInput() - .query(invocationData.getQuery()) - .operationName(invocationData.getOperationName()) - .variables(invocationData.getVariables()) - .build(); - customizeExecutionInput(executionInput, headers); - CompletableFuture customizedExecutionInput = customizeExecutionInput(executionInput, headers); - CompletableFuture executionResultCompletableFuture = customizedExecutionInput.thenCompose(graphQL::executeAsync); - return handleExecutionResult(executionResultCompletableFuture); - } - - protected CompletableFuture customizeExecutionInput(ExecutionInput executionInput, - ServerRequest.Headers headers) { - return CompletableFuture.completedFuture(executionInput); - } - - protected Object handleExecutionResult(CompletableFuture executionResultCF) { - if (executionResultCF.isDone()) { - return toSpecification(executionResultCF); - } - return executionResultCF.thenApply(ExecutionResult::toSpecification); - } - - private Map toSpecification(CompletableFuture executionResultCF) { - try { - return executionResultCF.get().toSpecification(); - } catch (Exception e) { - throw new RuntimeException("Should not happen", e); - } - } -} diff --git a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestBody.java b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLServletRequestBody.java similarity index 94% rename from spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestBody.java rename to spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLServletRequestBody.java index 666f08b3..6fd50364 100644 --- a/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLRequestBody.java +++ b/spring-graphql-webmvc/src/main/java/org/springframework/graphql/servlet/components/GraphQLServletRequestBody.java @@ -2,7 +2,7 @@ package org.springframework.graphql.servlet.components; import java.util.Map; -public class GraphQLRequestBody { +public class GraphQLServletRequestBody { private String query; private String operationName; private Map variables;