diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/DefaultWebGraphQlHandlerBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/web/DefaultWebGraphQlHandlerBuilder.java index 48f1da19..b43808dd 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/DefaultWebGraphQlHandlerBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/DefaultWebGraphQlHandlerBuilder.java @@ -119,13 +119,13 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { private WebInterceptorChain initWebInterceptorChain(List interceptors) { - WebInterceptorChain targetHandler = + WebInterceptorChain endOfChain = webInput -> service.execute(webInput).map((result) -> new WebOutput(webInput, result)); return interceptors.stream() .reduce(WebInterceptor::andThen) - .map((interceptor) -> (WebInterceptorChain) (input) -> interceptor.intercept(input, targetHandler)) - .orElse(targetHandler); + .map((interceptor) -> (WebInterceptorChain) (input) -> interceptor.intercept(input, endOfChain)) + .orElse(endOfChain); } @Nullable @@ -168,14 +168,12 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder { @Override public Mono handleWebSocketInitialization(Map payload) { - return this.delegate.handleWebSocketInitialization(payload).contextWrite((context) -> - ReactorContextManager.extractThreadLocalValues(this.accessor, context)); + return this.delegate.handleWebSocketInitialization(payload); } @Override public Mono handleWebSocketCompletion() { - return this.delegate.handleWebSocketCompletion().contextWrite((context) -> - ReactorContextManager.extractThreadLocalValues(this.accessor, context)); + return this.delegate.handleWebSocketCompletion(); } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/WebGraphQlHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/web/WebGraphQlHandler.java index fe29b457..fa889d44 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/WebGraphQlHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/WebGraphQlHandler.java @@ -25,8 +25,8 @@ import org.springframework.graphql.GraphQlService; import org.springframework.graphql.execution.ThreadLocalAccessor; /** - * Contract for common handling of a GraphQL request received over HTTP or - * WebSocket, and executed on Spring MVC or Spring WebFlux. + * Contract for common handling of a GraphQL request over HTTP or WebSocket, + * for use with Spring MVC or Spring WebFlux. * * @author Rossen Stoyanchev * @since 1.0.0 @@ -79,7 +79,12 @@ public interface WebGraphQlHandler { interface Builder { /** - * Configure interceptors to be invoked before the target {@code GraphQlService}. + * Configure interceptors to be invoked before the target + * {@code GraphQlService}. + *

One of the interceptors can be of type {@link WebSocketInterceptor} + * to handle data from the first {@code ConnectionInit} message expected + * on a GraphQL over WebSocket session, as well as the {@code Complete} + * message expected at the end of a session. * @param interceptors the interceptors to add * @return this builder */ diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptor.java b/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptor.java index 31f52b54..ca2d121b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptor.java @@ -24,16 +24,15 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.util.Assert; /** - * Interceptor for intercepting GraphQL over HTTP or WebSocket requests. Provides - * information about the HTTP request or WebSocket handshake, allows customization of the - * {@link ExecutionInput} and of the {@link ExecutionResult} from request execution. + * Interceptor for intercepting GraphQL over HTTP or GraphQL over WebSocket + * requests. Provides information about the HTTP request or WebSocket handshake, + * and allows customization of the {@link ExecutionInput} as well as of the + * {@link ExecutionResult}. * - *

- * Interceptors may be declared as beans in Spring configuration and ordered as defined in - * {@link ObjectProvider#orderedStream()}. + *

Interceptors are typically declared as beans in Spring configuration and + * ordered as defined in {@link ObjectProvider#orderedStream()}. * - *

- * Supported for Spring MVC and WebFlux. + *

Supported for Spring MVC and WebFlux. * * @author Rossen Stoyanchev * @since 1.0.0 @@ -41,18 +40,20 @@ import org.springframework.util.Assert; public interface WebInterceptor { /** - * Intercept a request and delegate for further handling and request execution via - * {@link WebGraphQlHandler#handleRequest(WebInput)}. - * @param webInput container with HTTP request information and options to customize - * the {@link ExecutionInput}. - * @param next the rest of the chain to delegate to for request execution + * Intercept a request and possibly delegate to the rest of the chain + * consisting of more interceptors as well as a + * {@link org.springframework.graphql.GraphQlService} at the end to actually + * handle the request through the GraphQL engine. + * @param webInput container for HTTP request information and options to + * customize the {@link ExecutionInput}. + * @param chain the rest of the chain to delegate to for request execution * @return a {@link Mono} with the result */ - Mono intercept(WebInput webInput, WebInterceptorChain next); + Mono intercept(WebInput webInput, WebInterceptorChain chain); /** - * Return a composed {@link WebInterceptor} that invokes the current interceptor first - * one and then the one one passed in. + * Return a composed {@link WebInterceptor} that invokes the current + * interceptor first and then the one one passed in. * @param interceptor the interceptor to compose the current one with * @return the composed WebInterceptor */ diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptorChain.java b/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptorChain.java index ccc6cbd4..d11c8638 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptorChain.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/WebInterceptorChain.java @@ -27,8 +27,9 @@ import reactor.core.publisher.Mono; public interface WebInterceptorChain { /** - * Delegate to the next rest of the chain which can consist of more - * {@code WebInterceptor} instances, and a {@link WebGraphQlHandler}. + * Delegate to the next rest of the chain consisting of more interceptors + * as well as a {@link org.springframework.graphql.GraphQlService} at the + * end to actually handle the request through the GraphQL engine. * @param webInput the input for the request * @return the output with the result from request execution */ diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/WebSocketInterceptor.java b/spring-graphql/src/main/java/org/springframework/graphql/web/WebSocketInterceptor.java index 2cb6e55f..fca883c5 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/WebSocketInterceptor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/WebSocketInterceptor.java @@ -30,8 +30,8 @@ import reactor.core.publisher.Mono; public interface WebSocketInterceptor extends WebInterceptor { @Override - default Mono intercept(WebInput webInput, WebInterceptorChain next) { - return next.next(webInput); + default Mono intercept(WebInput webInput, WebInterceptorChain chain) { + return chain.next(webInput); } /** diff --git a/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java b/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java index 39e356db..9ca35590 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java @@ -68,13 +68,12 @@ public abstract class GraphQlTestUtils { return (T) map.get(key); } - @SuppressWarnings("unchecked") public static T checkErrorsAndGetData(@Nullable ExecutionResult result) { assertThat(result).isNotNull(); assertThat(result.getErrors()).as("Errors present in GraphQL response").isEmpty(); T data = result.getData(); assertThat(data).isNotNull(); - return (T) data; + return data; } } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/web/ConsumeOneAndNeverCompleteInterceptor.java b/spring-graphql/src/test/java/org/springframework/graphql/web/ConsumeOneAndNeverCompleteInterceptor.java index 3607bbd3..223d6e4c 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/web/ConsumeOneAndNeverCompleteInterceptor.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/web/ConsumeOneAndNeverCompleteInterceptor.java @@ -25,8 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat; public class ConsumeOneAndNeverCompleteInterceptor implements WebInterceptor { @Override - public Mono intercept(WebInput webInput, WebInterceptorChain next) { - return next.next(webInput).map((output) -> output.transform((builder) -> { + public Mono intercept(WebInput webInput, WebInterceptorChain chain) { + return chain.next(webInput).map((output) -> output.transform((builder) -> { Publisher publisher = output.getData(); assertThat(publisher).isNotNull(); builder.data(Flux.from(publisher).take(1).concatWith(Flux.never())); diff --git a/spring-graphql/src/test/java/org/springframework/graphql/web/WebInterceptorTests.java b/spring-graphql/src/test/java/org/springframework/graphql/web/WebInterceptorTests.java index 9894adb6..4ef8f5fa 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/web/WebInterceptorTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/web/WebInterceptorTests.java @@ -105,9 +105,9 @@ public class WebInterceptorTests { } @Override - public Mono intercept(WebInput input, WebInterceptorChain next) { + public Mono intercept(WebInput input, WebInterceptorChain chain) { this.output.append(":pre").append(this.order); - return next.next(input) + return chain.next(input) .map((output) -> { this.output.append(":post").append(this.order); return output;