Refactor webmvc to use the new Handler

This commit is contained in:
Andreas Marek
2020-09-14 07:28:49 +10:00
parent a37aa740a9
commit f2cf46989b
6 changed files with 52 additions and 95 deletions

View File

@@ -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")

View File

@@ -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")

View File

@@ -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<String, Object> variables;
public GraphQLInvocationData(String query, String operationName, Map<String, Object> 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<String, Object> getVariables() {
return variables;
}
}

View File

@@ -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<ServerResponse> 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<String, Object> variables = body.getVariables();
if (variables == null) {
variables = Collections.emptyMap();
}
GraphQLRequestBody graphQLRequestBody = new GraphQLRequestBody(query, body.getOperationName(), variables);
Mono<Map<String, Object>> 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<String, Object> 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);
}
}

View File

@@ -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<ExecutionInput> customizedExecutionInput = customizeExecutionInput(executionInput, headers);
CompletableFuture<ExecutionResult> executionResultCompletableFuture = customizedExecutionInput.thenCompose(graphQL::executeAsync);
return handleExecutionResult(executionResultCompletableFuture);
}
protected CompletableFuture<ExecutionInput> customizeExecutionInput(ExecutionInput executionInput,
ServerRequest.Headers headers) {
return CompletableFuture.completedFuture(executionInput);
}
protected Object handleExecutionResult(CompletableFuture<ExecutionResult> executionResultCF) {
if (executionResultCF.isDone()) {
return toSpecification(executionResultCF);
}
return executionResultCF.thenApply(ExecutionResult::toSpecification);
}
private Map<String, Object> toSpecification(CompletableFuture<ExecutionResult> executionResultCF) {
try {
return executionResultCF.get().toSpecification();
} catch (Exception e) {
throw new RuntimeException("Should not happen", e);
}
}
}

View File

@@ -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<String, Object> variables;