Expose ExecutionInput in WebOutput

WebOutput now exposes the ExecutionInput prepared for the request and
no longer provides access to the WebInput which is already available
to a WebInterceptor.

Closes gh-229
This commit is contained in:
rstoyanchev
2022-01-07 21:27:08 +00:00
parent c84f342daf
commit 22985efe6a
8 changed files with 47 additions and 40 deletions

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLError;
@@ -352,9 +353,10 @@ public class GraphQlTesterTests {
if (!CollectionUtils.isEmpty(errors)) {
builder.addErrors(errors);
}
RequestInput input = new RequestInput("{}", null, null, null, "1");
ExecutionInput executionInput = ExecutionInput.newExecutionInput("{}").build();
ExecutionResult result = builder.build();
given(this.service.execute(this.inputCaptor.capture())).willReturn(Mono.just(new RequestOutput(input, result)));
given(this.service.execute(this.inputCaptor.capture()))
.willReturn(Mono.just(new RequestOutput(executionInput, result)));
}
}

View File

@@ -26,6 +26,7 @@ import java.util.stream.Stream;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLError;
@@ -38,6 +39,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Mono;
import org.springframework.graphql.RequestOutput;
import org.springframework.graphql.web.WebGraphQlHandler;
import org.springframework.graphql.web.WebInput;
import org.springframework.graphql.web.WebOutput;
@@ -271,8 +273,9 @@ public class WebGraphQlTesterTests {
if (!CollectionUtils.isEmpty(errors)) {
builder.addErrors(errors);
}
ExecutionInput executionInput = ExecutionInput.newExecutionInput("{}").build();
ExecutionResult result = builder.build();
WebOutput output = new WebOutput(mock(WebInput.class), result);
WebOutput output = new WebOutput(new RequestOutput(executionInput, result));
given(this.handler.handleRequest(this.bodyCaptor.capture())).willReturn(Mono.just(output));
}

View File

@@ -19,8 +19,7 @@ package org.springframework.graphql;
import reactor.core.publisher.Mono;
/**
* Strategy to perform GraphQL request execution with input for and output from the
* invocation of {@link graphql.GraphQL}.
* Strategy to perform a GraphQL request.
*
* @author Rossen Stoyanchev
* @since 1.0.0
@@ -29,8 +28,8 @@ public interface GraphQlService {
/**
* Perform the operation and return the result.
* @param input container for the GraphQL request input
* @return the execution result
* @param input container for GraphQL request input
* @return the result from execution
*/
Mono<RequestOutput> execute(RequestInput input);

View File

@@ -18,6 +18,7 @@ package org.springframework.graphql;
import java.util.List;
import java.util.Map;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.GraphQLError;
@@ -25,36 +26,38 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* An {@link ExecutionResult} that also holds the {@link RequestInput}.
* Wraps an {@link ExecutionResult} and also exposes the {@link ExecutionInput}
* prepared for the request.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
public class RequestOutput implements ExecutionResult {
private final RequestInput requestInput;
private final ExecutionInput executionInput;
private final ExecutionResult executionResult;
/**
* Create an instance that wraps the given {@link ExecutionResult}.
* @param requestInput the container for the GraphQL input
* @param executionResult the result of performing a graphql query
* Create an instance.
* @param executionInput the input prepared for the request
* @param executionResult the result from performing the request
*/
public RequestOutput(RequestInput requestInput, ExecutionResult executionResult) {
Assert.notNull(requestInput, "RequestInput is required.");
public RequestOutput(ExecutionInput executionInput, ExecutionResult executionResult) {
Assert.notNull(executionInput, "ExecutionInput is required.");
Assert.notNull(executionResult, "ExecutionResult is required.");
this.requestInput = requestInput;
this.executionInput = executionInput;
this.executionResult = executionResult;
}
/**
* Return the associated {@link RequestInput} used for the execution.
* @return the associated WebInput
* Return the {@link ExecutionInput} that was prepared from the
* {@link RequestInput} and passed to {@link graphql.GraphQL}.
*/
public RequestInput getRequestInput() {
return this.requestInput;
public ExecutionInput getExecutionInput() {
return this.executionInput;
}
@Nullable

View File

@@ -63,9 +63,9 @@ public class ExecutionGraphQlService implements GraphQlService {
return Mono.deferContextual((contextView) -> {
ExecutionInput executionInput = requestInput.toExecutionInput();
ReactorContextManager.setReactorContext(contextView, executionInput);
executionInput = registerDataLoaders(executionInput);
return Mono.fromFuture(this.graphQlSource.graphQl().executeAsync(executionInput))
.map(result -> new RequestOutput(requestInput, result));
ExecutionInput updatedExecutionInput = registerDataLoaders(executionInput);
return Mono.fromFuture(this.graphQlSource.graphQl().executeAsync(updatedExecutionInput))
.map(result -> new RequestOutput(updatedExecutionInput, result));
});
}

View File

@@ -119,12 +119,11 @@ class DefaultWebGraphQlHandlerBuilder implements WebGraphQlHandler.Builder {
private WebInterceptorChain initWebInterceptorChain(List<WebInterceptor> interceptors) {
WebInterceptorChain endOfChain =
webInput -> service.execute(webInput).map((result) -> new WebOutput(webInput, result));
WebInterceptorChain endOfChain = webInput -> this.service.execute(webInput).map(WebOutput::new);
return interceptors.stream()
.reduce(WebInterceptor::andThen)
.map((interceptor) -> (WebInterceptorChain) (input) -> interceptor.intercept(input, endOfChain))
.map(interceptor -> (WebInterceptorChain) (input) -> interceptor.intercept(input, endOfChain))
.orElse(endOfChain);
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLError;
@@ -45,24 +46,21 @@ public class WebOutput extends RequestOutput {
/**
* Create an instance that wraps the given {@link ExecutionResult}.
* @param input the container for the GraphQL input
* @param executionResult the result of performing a graphql query
* @param requestOutput the output from an executed request
*/
public WebOutput(WebInput input, ExecutionResult executionResult) {
this(input, executionResult, null);
public WebOutput(RequestOutput requestOutput) {
this(requestOutput.getExecutionInput(), requestOutput, null);
}
private WebOutput(WebInput input, ExecutionResult executionResult, @Nullable HttpHeaders responseHeaders) {
super(input, executionResult);
private WebOutput(
ExecutionInput executionInput, ExecutionResult executionResult,
@Nullable HttpHeaders responseHeaders) {
super(executionInput, executionResult);
this.responseHeaders = responseHeaders;
}
@Override
public WebInput getRequestInput() {
return (WebInput) super.getRequestInput();
}
/**
* Return a read-only view of any custom headers to be added to the HTTP response, or
* {@code null} until {@link #transform(Consumer)} is used to add such headers.
@@ -93,7 +91,7 @@ public class WebOutput extends RequestOutput {
*/
public static final class Builder {
private final WebInput input;
private final ExecutionInput executionInput;
@Nullable
private Object data;
@@ -107,7 +105,7 @@ public class WebOutput extends RequestOutput {
private HttpHeaders headers;
private Builder(WebOutput output) {
this.input = output.getRequestInput();
this.executionInput = output.getExecutionInput();
this.data = output.getData();
this.errors = output.getErrors();
this.extensions = output.getExtensions();
@@ -187,7 +185,7 @@ public class WebOutput extends RequestOutput {
public WebOutput build() {
ExecutionResult result = new ExecutionResultImpl(this.data, this.errors, this.extensions);
return new WebOutput(this.input, result, this.headers);
return new WebOutput(this.executionInput, result, this.headers);
}
}

View File

@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import graphql.ExecutionInput;
import graphql.ExecutionResultImpl;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
@@ -92,7 +93,9 @@ public class WebInterceptorTests {
}
private Mono<RequestOutput> emptyExecutionResult(RequestInput input) {
return Mono.just(new RequestOutput(input, ExecutionResultImpl.newExecutionResult().build()));
return Mono.just(new RequestOutput(
ExecutionInput.newExecutionInput("{}").build(),
ExecutionResultImpl.newExecutionResult().build()));
}
private static class OrderInterceptor implements WebInterceptor {