refactor to use router functions, upgrade spring and gradle

This commit is contained in:
Andreas Marek
2020-08-09 11:59:12 +10:00
committed by Rossen Stoyanchev
parent 84806f6a6b
commit 932093ac34
14 changed files with 104 additions and 171 deletions

View File

@@ -13,8 +13,8 @@ subprojects {
ext {
graphqlJavaVersion = "15.0"
springVersion = "5.1.7.RELEASE"
springBootVersion = "2.1.5.RELEASE"
springVersion = "5.2.8.RELEASE"
springBootVersion = "2.3.2.RELEASE"
jacksonVersion = "2.9.8"
assertJVersion = "3.11.1"
}
@@ -42,7 +42,7 @@ subprojects {
}
task myWrapper(type: Wrapper) {
gradleVersion = '4.10.2'
gradleVersion = '6.5.1'
distributionUrl = "https://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip"
}

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,7 +1,7 @@
description = "GraphQL Java Spring Boot starter Webmvc"
dependencies {
compile "org.springframework.boot:spring-boot-autoconfigure:$springBootVersion"
compile project(':graphql-java-spring-webmvc')
implementation "org.springframework.boot:spring-boot-autoconfigure:$springBootVersion"
implementation project(':graphql-java-spring-webmvc')
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
testCompile "org.springframework.boot:spring-boot-starter-web:$springBootVersion"

View File

@@ -1,15 +1,17 @@
description = "GraphQL Java Spring Webmvc integration"
dependencies {
compile "org.springframework:spring-webmvc:$springVersion"
compile "org.springframework:spring-context:$springVersion"
compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
compile "com.graphql-java:graphql-java:$graphqlJavaVersion"
apply plugin: 'java-library'
testCompile("org.assertj:assertj-core:$assertJVersion")
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile "org.springframework:spring-test:$springVersion"
testCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
testCompile group: 'com.jayway.jsonpath', name: 'json-path', version: '2.4.0'
testCompile "org.mockito:mockito-core:2.+"
dependencies {
implementation "org.springframework:spring-webmvc:$springVersion"
implementation "org.springframework:spring-context:$springVersion"
implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
api "com.graphql-java:graphql-java:$graphqlJavaVersion"
implementation group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
testImplementation("org.assertj:assertj-core:$assertJVersion")
testImplementation group: 'junit', name: 'junit', version: '4.12'
testImplementation "org.springframework:spring-test:$springVersion"
testImplementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.4.0'
testImplementation "org.mockito:mockito-core:2.+"
}

View File

@@ -1,20 +0,0 @@
package org.springframework.graphql;
import graphql.ExecutionInput;
import graphql.PublicApi;
import org.springframework.web.context.request.WebRequest;
import java.util.concurrent.CompletableFuture;
/**
* Lets you customize the #ExecutionInput before the query is executed.
* You can for example set a context object or define a root value.
* <p>
* This is only used if you use the default {@link GraphQLInvocation}.
*/
@PublicApi
public interface ExecutionInputCustomizer {
CompletableFuture<ExecutionInput> customizeExecutionInput(ExecutionInput executionInput, WebRequest webRequest);
}

View File

@@ -1,12 +0,0 @@
package org.springframework.graphql;
import graphql.ExecutionResult;
import graphql.PublicSpi;
import java.util.concurrent.CompletableFuture;
@PublicSpi
public interface ExecutionResultHandler {
Object handleExecutionResult(CompletableFuture<ExecutionResult> executionResultCF);
}

View File

@@ -1,14 +0,0 @@
package org.springframework.graphql;
import graphql.ExecutionResult;
import graphql.PublicApi;
import org.springframework.web.context.request.WebRequest;
import java.util.concurrent.CompletableFuture;
@PublicApi
public interface GraphQLInvocation {
CompletableFuture<ExecutionResult> invoke(GraphQLInvocationData invocationData, WebRequest webRequest);
}

View File

@@ -1,12 +1,10 @@
package org.springframework.graphql;
import graphql.Assert;
import graphql.PublicApi;
import java.util.Collections;
import java.util.Map;
@PublicApi
public class GraphQLInvocationData {
private final String query;

View File

@@ -1,19 +0,0 @@
package org.springframework.graphql.components;
import graphql.ExecutionInput;
import graphql.Internal;
import org.springframework.graphql.ExecutionInputCustomizer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
import java.util.concurrent.CompletableFuture;
@Component
@Internal
public class DefaultExecutionInputCustomizer implements ExecutionInputCustomizer {
@Override
public CompletableFuture<ExecutionInput> customizeExecutionInput(ExecutionInput executionInput, WebRequest webRequest) {
return CompletableFuture.completedFuture(executionInput);
}
}

View File

@@ -1,23 +0,0 @@
package org.springframework.graphql.components;
import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.ExecutionResult;
import graphql.Internal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.ExecutionResultHandler;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
@Component
@Internal
public class DefaultExecutionResultHandler implements ExecutionResultHandler {
@Autowired
ObjectMapper objectMapper;
@Override
public Object handleExecutionResult(CompletableFuture<ExecutionResult> executionResultCF) {
return executionResultCF.thenApply(ExecutionResult::toSpecification);
}
}

View File

@@ -1,37 +0,0 @@
package org.springframework.graphql.components;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.Internal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.ExecutionInputCustomizer;
import org.springframework.graphql.GraphQLInvocation;
import org.springframework.graphql.GraphQLInvocationData;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
import java.util.concurrent.CompletableFuture;
@Component
@Internal
public class DefaultGraphQLInvocation implements GraphQLInvocation {
@Autowired
GraphQL graphQL;
@Autowired
ExecutionInputCustomizer executionInputCustomizer;
@Override
public CompletableFuture<ExecutionResult> invoke(GraphQLInvocationData invocationData, WebRequest webRequest) {
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(invocationData.getQuery())
.operationName(invocationData.getOperationName())
.variables(invocationData.getVariables())
.build();
CompletableFuture<ExecutionInput> customizedExecutionInput = executionInputCustomizer.customizeExecutionInput(executionInput, webRequest);
return customizedExecutionInput.thenCompose(graphQL::executeAsync);
}
}

View File

@@ -1,43 +1,49 @@
package org.springframework.graphql.components;
import graphql.ExecutionResult;
import graphql.Internal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.ExecutionResultHandler;
import org.springframework.graphql.GraphQLInvocation;
import org.springframework.context.annotation.Bean;
import org.springframework.graphql.GraphQLInvocationData;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
import java.util.concurrent.CompletableFuture;
import java.io.IOException;
@RestController
@Internal
import static org.springframework.web.servlet.function.RouterFunctions.route;
@Component
public class GraphQLController {
@Autowired
GraphQLInvocation graphQLInvocation;
GraphQLRequestHandler graphQLRequestHandler;
@Autowired
ExecutionResultHandler executionResultHandler;
@Bean
public RouterFunction<ServerResponse> routerFunction() {
RouterFunction<ServerResponse> route = route()
.POST("/graphql", this::graphqlPOST)
.build();
return route;
@RequestMapping(value = "${graphql.url:graphql}",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Object graphqlPOST(@RequestBody GraphQLRequestBody body,
WebRequest webRequest) {
}
private ServerResponse graphqlPOST(ServerRequest serverRequest) {
GraphQLRequestBody body = null;
try {
body = serverRequest.body(GraphQLRequestBody.class);
} catch (javax.servlet.ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String query = body.getQuery();
if (query == null) {
query = "";
}
CompletableFuture<ExecutionResult> executionResult = graphQLInvocation.invoke(new GraphQLInvocationData(query, body.getOperationName(), body.getVariables()), webRequest);
return executionResultHandler.handleExecutionResult(executionResult);
GraphQLInvocationData invocationData = new GraphQLInvocationData(query, body.getOperationName(), body.getVariables());
Object resultBody = graphQLRequestHandler.invoke(invocationData, serverRequest.headers());
return ServerResponse.ok().body(resultBody);
}
}

View File

@@ -1,10 +1,7 @@
package org.springframework.graphql.components;
import graphql.Internal;
import java.util.Map;
@Internal
public class GraphQLRequestBody {
private String query;
private String operationName;

View File

@@ -0,0 +1,55 @@
package org.springframework.graphql.components;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.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);
}
}
}