From b5d4fe18ab59daad0bde766f6517fc308c0f448b Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 28 Sep 2020 11:18:42 +0100 Subject: [PATCH] Javadoc updates and rename WebInterceptorExecution --- .../graphql/WebFluxGraphQLHandler.java | 11 +++++- .../org/springframework/graphql/WebInput.java | 37 ++++++++++++++++++- .../graphql/WebInterceptor.java | 26 ++++++++++--- ...java => WebInterceptorExecutionChain.java} | 6 ++- .../graphql/WebMvcGraphQLHandler.java | 11 +++++- .../springframework/graphql/WebOutput.java | 3 ++ ...=> WebInterceptorExecutionChainTests.java} | 6 +-- 7 files changed, 84 insertions(+), 16 deletions(-) rename spring-graphql-web/src/main/java/org/springframework/graphql/{WebInterceptorExecution.java => WebInterceptorExecutionChain.java} (91%) rename spring-graphql-web/src/test/java/org/springframework/graphql/{WebInterceptorExecutionTests.java => WebInterceptorExecutionChainTests.java} (94%) diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebFluxGraphQLHandler.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebFluxGraphQLHandler.java index 1ac4031a..55398c17 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebFluxGraphQLHandler.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebFluxGraphQLHandler.java @@ -30,11 +30,18 @@ import org.springframework.web.reactive.function.server.ServerResponse; */ public class WebFluxGraphQLHandler implements HandlerFunction { - private final WebInterceptorExecution executionChain; + private final WebInterceptorExecutionChain executionChain; + /** + * Create a handler that executes queries through the given {@link GraphQL} + * and and invokes the given interceptors to customize input to and the + * result from the execution of the query. + * @param graphQL the GraphQL instance to use for query execution + * @param interceptors 0 or more interceptors to customize input and output + */ public WebFluxGraphQLHandler(GraphQL graphQL, List interceptors) { - this.executionChain = new WebInterceptorExecution(graphQL, interceptors); + this.executionChain = new WebInterceptorExecutionChain(graphQL, interceptors); } diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInput.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInput.java index 06f38b95..2d999570 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInput.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInput.java @@ -24,14 +24,16 @@ import graphql.ExecutionInput; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; import org.springframework.lang.Nullable; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebInputException; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; /** - * Container for input from an HTTP request to a GraphQL endpoint, including - * URI, headers, and other inputs extracted from the body of the request. + * Container for the input of a GraphQL query over HTTP. The input includes the + * {@link UriComponents URL} and the headers of the request, as well as the + * query name, operation name, and variables from the request body. */ public class WebInput { @@ -69,27 +71,51 @@ public class WebInput { } + /** + * Return the URI of the HTTP request including + * {@link UriComponents#getQueryParams() query parameters}. + */ public UriComponents uri() { return this.uri; } + /** + * Return the headers of the request. + */ public HttpHeaders headers() { return this.headers; } + /** + * Return the query name extracted from the request body. This is guaranteed + * to be a non-empty string, or otherwise the request is rejected via + * {@link ServerWebInputException} as a 400 error. + */ public String query() { return this.query; } + /** + * Return the query operation name extracted from the request body or + * {@code null} if not provided. + */ @Nullable public String operationName() { return this.operationName; } + /** + * Return the query variables that can be referenced via $syntax extracted + * from the request body or a {@code null} if not provided. + */ public Map variables() { return this.variables; } + /** + * Create an {@link ExecutionInput} initialized with the {@link #query()}, + * {@link #operationName()}, and {@link #variables()}. + */ public ExecutionInput toExecutionInput() { return ExecutionInput.newExecutionInput() .query(query()) @@ -98,4 +124,11 @@ public class WebInput { .build(); } + @Override + public String toString() { + return "WebInput [" + uri() + " " + headers() + ", query='" + query() + "'" + + (operationName() != null ? ", operationName='" + operationName() + "'" : "") + + (!CollectionUtils.isEmpty(variables()) ? ", variables=" + variables() : "") + + "]"; + } } \ No newline at end of file diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptor.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptor.java index d388f229..cec5c2d5 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptor.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptor.java @@ -18,20 +18,32 @@ package org.springframework.graphql; import java.util.function.Consumer; import graphql.ExecutionInput; -import graphql.GraphQL; +import graphql.ExecutionResult; import reactor.core.publisher.Mono; /** - * Interceptor for GraphQL over HTTP requests that allows customization of the - * {@link ExecutionInput} and the {@link graphql.ExecutionResult} of - * {@link GraphQL} query execution. + * Web interceptor for GraphQL queries over HTTP. The interceptor allows + * customization of the {@link ExecutionInput} for the query as well as the + * {@link ExecutionResult} of the query and is supported for both Spring MVC and + * Spring WebFlux. + * + *

A list of interceptors may be provided to {@link WebMvcGraphQLHandler} or + * to {@link WebFluxGraphQLHandler}. Interceptors are executed in that provided + * order where each interceptor sees the {@code ExecutionInput} or the + * {@code ExecutionResult} that was customized by the previous interceptor. */ public interface WebInterceptor { /** * Intercept a GraphQL over HTTP request before the query is executed. * - * @param executionInput the input to use, initialized from the {@code WebInput} + *

{@code ExecutionInput} is initially populated with the input from the + * request body via {@link WebInput#toExecutionInput()} where the + * {@link WebInput#query() query} is guaranteed to be a non-empty String. + * Interceptors are then executed in order to further customize the input + * and or perform other actions or checks. + * + * @param executionInput the input to use, initialized from {@code WebInput} * @param webInput the input from the HTTP request * @return the same instance or a new one via {@link ExecutionInput#transform(Consumer)} */ @@ -42,6 +54,10 @@ public interface WebInterceptor { /** * Intercept a GraphQL over HTTP request after the query is executed. * + *

{@code WebOutput} initially wraps the {@link ExecutionResult} returned + * from the execution of the query. Interceptors are then executed in order + * to further customize it and/or perform other actions. + * * @param webOutput the execution result * @return the same instance or a new one via {@link WebOutput#transform(Consumer)} */ diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecution.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecutionChain.java similarity index 91% rename from spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecution.java rename to spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecutionChain.java index 12239e18..dd5168a2 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecution.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptorExecutionChain.java @@ -25,6 +25,7 @@ import graphql.ExecutionResult; import graphql.GraphQL; import reactor.core.publisher.Mono; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** @@ -32,14 +33,15 @@ import org.springframework.util.CollectionUtils; * {@link ExecutionInput} and the {@link ExecutionResult} of {@link GraphQL} * query execution. */ -class WebInterceptorExecution { +class WebInterceptorExecutionChain { private final GraphQL graphQL; private final List interceptors; - WebInterceptorExecution(GraphQL graphQL, List interceptors) { + WebInterceptorExecutionChain(GraphQL graphQL, List interceptors) { + Assert.notNull(graphQL, "GraphQL is required"); this.graphQL = graphQL; this.interceptors = (!CollectionUtils.isEmpty(interceptors) ? Collections.unmodifiableList(new ArrayList<>(interceptors)) : Collections.emptyList()); diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebMvcGraphQLHandler.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebMvcGraphQLHandler.java index e0817840..16159031 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebMvcGraphQLHandler.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebMvcGraphQLHandler.java @@ -37,11 +37,18 @@ import org.springframework.web.servlet.function.ServerResponse; */ public class WebMvcGraphQLHandler implements HandlerFunction { - private final WebInterceptorExecution executionChain; + private final WebInterceptorExecutionChain executionChain; + /** + * Create a handler that executes queries through the given {@link GraphQL} + * and and invokes the given interceptors to customize input to and the + * result from the execution of the query. + * @param graphQL the GraphQL instance to use for query execution + * @param interceptors 0 or more interceptors to customize input and output + */ public WebMvcGraphQLHandler(GraphQL graphQL, List interceptors) { - this.executionChain = new WebInterceptorExecution(graphQL, interceptors); + this.executionChain = new WebInterceptorExecutionChain(graphQL, interceptors); } diff --git a/spring-graphql-web/src/main/java/org/springframework/graphql/WebOutput.java b/spring-graphql-web/src/main/java/org/springframework/graphql/WebOutput.java index 9cdfa53f..9f136d0c 100644 --- a/spring-graphql-web/src/main/java/org/springframework/graphql/WebOutput.java +++ b/spring-graphql-web/src/main/java/org/springframework/graphql/WebOutput.java @@ -35,6 +35,9 @@ public class WebOutput implements ExecutionResult { private final ExecutionResult executionResult; + /** + * Create an instance that wraps the given {@link ExecutionResult}. + */ public WebOutput(ExecutionResult executionResult) { this.executionResult = executionResult; } diff --git a/spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionTests.java b/spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionChainTests.java similarity index 94% rename from spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionTests.java rename to spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionChainTests.java index 5fb5d13f..e43503b5 100644 --- a/spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionTests.java +++ b/spring-graphql-web/src/test/java/org/springframework/graphql/WebInterceptorExecutionChainTests.java @@ -41,9 +41,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * Unit tests for {@link WebInterceptorExecution}. + * Unit tests for {@link WebInterceptorExecutionChain}. */ -public class WebInterceptorExecutionTests { +public class WebInterceptorExecutionChainTests { @Test void testInterceptorInvocation() throws Exception { @@ -65,7 +65,7 @@ public class WebInterceptorExecutionTests { Map body = mapper.reader().readValue("{\"query\": \"" + query + "\"}", Map.class); WebInput webInput = new WebInput(URI.create("/graphql"), new HttpHeaders(), body); - WebOutput webOutput = new WebInterceptorExecution(createGraphQL(), interceptors) + WebOutput webOutput = new WebInterceptorExecutionChain(createGraphQL(), interceptors) .execute(webInput).block(); assertEquals(":pre1:pre2:pre3:post3:post2:post1", sb.toString());