Polishing

See gh-162
This commit is contained in:
Rossen Stoyanchev
2021-10-21 15:53:45 +01:00
parent 20bae75ed8
commit 69e34baadf
8 changed files with 40 additions and 36 deletions

View File

@@ -119,13 +119,13 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder {
private WebInterceptorChain initWebInterceptorChain(List<WebInterceptor> 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<Object> handleWebSocketInitialization(Map<String, Object> payload) {
return this.delegate.handleWebSocketInitialization(payload).contextWrite((context) ->
ReactorContextManager.extractThreadLocalValues(this.accessor, context));
return this.delegate.handleWebSocketInitialization(payload);
}
@Override
public Mono<Void> handleWebSocketCompletion() {
return this.delegate.handleWebSocketCompletion().contextWrite((context) ->
ReactorContextManager.extractThreadLocalValues(this.accessor, context));
return this.delegate.handleWebSocketCompletion();
}
}

View File

@@ -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}.
* <p>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
*/

View File

@@ -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}.
*
* <p>
* Interceptors may be declared as beans in Spring configuration and ordered as defined in
* {@link ObjectProvider#orderedStream()}.
* <p> Interceptors are typically declared as beans in Spring configuration and
* ordered as defined in {@link ObjectProvider#orderedStream()}.
*
* <p>
* Supported for Spring MVC and WebFlux.
* <p> 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<WebOutput> intercept(WebInput webInput, WebInterceptorChain next);
Mono<WebOutput> 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
*/

View File

@@ -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
*/

View File

@@ -30,8 +30,8 @@ import reactor.core.publisher.Mono;
public interface WebSocketInterceptor extends WebInterceptor {
@Override
default Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain next) {
return next.next(webInput);
default Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
return chain.next(webInput);
}
/**

View File

@@ -68,13 +68,12 @@ public abstract class GraphQlTestUtils {
return (T) map.get(key);
}
@SuppressWarnings("unchecked")
public static <T> 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;
}
}

View File

@@ -25,8 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ConsumeOneAndNeverCompleteInterceptor implements WebInterceptor {
@Override
public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain next) {
return next.next(webInput).map((output) -> output.transform((builder) -> {
public Mono<WebOutput> 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()));

View File

@@ -105,9 +105,9 @@ public class WebInterceptorTests {
}
@Override
public Mono<WebOutput> intercept(WebInput input, WebInterceptorChain next) {
public Mono<WebOutput> 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;