Skip to content

Commit

Permalink
Javadoc updates and rename WebInterceptorExecution
Browse files Browse the repository at this point in the history
  • Loading branch information
rstoyanchev committed Sep 28, 2020
1 parent 1f1ce72 commit b5d4fe1
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@
*/
public class WebFluxGraphQLHandler implements HandlerFunction<ServerResponse> {

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<WebInterceptor> interceptors) {
this.executionChain = new WebInterceptorExecution(graphQL, interceptors);
this.executionChain = new WebInterceptorExecutionChain(graphQL, interceptors);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@
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 {

Expand Down Expand Up @@ -69,27 +71,51 @@ private static String getAndValidateQuery(Map<String, Object> body) {
}


/**
* 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<String, Object> 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())
Expand All @@ -98,4 +124,11 @@ public ExecutionInput toExecutionInput() {
.build();
}

@Override
public String toString() {
return "WebInput [" + uri() + " " + headers() + ", query='" + query() + "'" +
(operationName() != null ? ", operationName='" + operationName() + "'" : "") +
(!CollectionUtils.isEmpty(variables()) ? ", variables=" + variables() : "") +
"]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,32 @@
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.
*
* <p>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}
* <p>{@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)}
*/
Expand All @@ -42,6 +54,10 @@ default Mono<ExecutionInput> preHandle(ExecutionInput executionInput, WebInput w
/**
* Intercept a GraphQL over HTTP request after the query is executed.
*
* <p>{@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)}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,23 @@
import graphql.GraphQL;
import reactor.core.publisher.Mono;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
* Supports the use of {@link WebInterceptor}s to customize the
* {@link ExecutionInput} and the {@link ExecutionResult} of {@link GraphQL}
* query execution.
*/
class WebInterceptorExecution {
class WebInterceptorExecutionChain {

private final GraphQL graphQL;

private final List<WebInterceptor> interceptors;


WebInterceptorExecution(GraphQL graphQL, List<WebInterceptor> interceptors) {
WebInterceptorExecutionChain(GraphQL graphQL, List<WebInterceptor> interceptors) {
Assert.notNull(graphQL, "GraphQL is required");
this.graphQL = graphQL;
this.interceptors = (!CollectionUtils.isEmpty(interceptors) ?
Collections.unmodifiableList(new ArrayList<>(interceptors)) : Collections.emptyList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,18 @@
*/
public class WebMvcGraphQLHandler implements HandlerFunction<ServerResponse> {

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<WebInterceptor> interceptors) {
this.executionChain = new WebInterceptorExecution(graphQL, interceptors);
this.executionChain = new WebInterceptorExecutionChain(graphQL, interceptors);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
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 {
Expand All @@ -65,7 +65,7 @@ void testInterceptorInvocation() throws Exception {
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());
Expand Down

0 comments on commit b5d4fe1

Please sign in to comment.