Extract ExecutionGraphQl[Request|Response] interfaces

Rename the implementation classes Request[Input|Output] accordingly to
match the interfaces, and move them into the support package.

Create AbstractGraphQlResponse in the support package that
pre-implements response field access.

This leaves mainly contracts in the top-level package.

See gh-332
This commit is contained in:
rstoyanchev
2022-03-18 21:27:09 +00:00
parent be05b031d6
commit 182e9e66f0
41 changed files with 623 additions and 452 deletions

View File

@@ -23,10 +23,13 @@ import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.GraphQlResponseError;
import org.springframework.graphql.RequestOutput;
import org.springframework.graphql.support.DefaultExecutionGraphQlRequest;
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse;
import org.springframework.graphql.client.GraphQlTransport;
import org.springframework.test.util.AssertionErrors;
import org.springframework.util.AlternativeJdkIdGenerator;
@@ -47,22 +50,22 @@ abstract class AbstractDirectTransport implements GraphQlTransport {
@Override
public Mono<GraphQlResponse> execute(GraphQlRequest request) {
return executeInternal(request).cast(GraphQlResponse.class);
return executeInternal(toExecutionRequest(request)).cast(GraphQlResponse.class);
}
@SuppressWarnings({"ConstantConditions", "unchecked"})
@Override
public Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
return executeInternal(request).flatMapMany(output -> {
return executeInternal(toExecutionRequest(request)).flatMapMany(response -> {
try {
Object data = output.getData();
Object data = response.getData();
AssertionErrors.assertTrue("Not a Publisher: " + data, data instanceof Publisher);
List<GraphQlResponseError> errors = output.getErrors();
List<GraphQlResponseError> errors = response.getErrors();
AssertionErrors.assertTrue("Subscription errors: " + errors, CollectionUtils.isEmpty(errors));
return Flux.from((Publisher<ExecutionResult>) data)
.map(result -> new RequestOutput(output.getExecutionInput(), result));
return Flux.from((Publisher<ExecutionResult>) data).map(executionResult ->
new DefaultExecutionGraphQlResponse(response.getExecutionInput(), executionResult));
}
catch (AssertionError ex) {
throw new AssertionError(ex.getMessage() + "\nRequest: " + request, ex);
@@ -70,9 +73,15 @@ abstract class AbstractDirectTransport implements GraphQlTransport {
});
}
private ExecutionGraphQlRequest toExecutionRequest(GraphQlRequest request) {
return new DefaultExecutionGraphQlRequest(
request.getDocument(), request.getOperationName(), request.getVariables(),
idGenerator.generateId().toString(), null);
}
/**
* Subclasses must implement this to execute requests.
*/
protected abstract Mono<? extends RequestOutput> executeInternal(GraphQlRequest request);
protected abstract Mono<ExecutionGraphQlResponse> executeInternal(ExecutionGraphQlRequest request);
}

View File

@@ -34,7 +34,7 @@ import com.jayway.jsonpath.TypeRef;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.graphql.DefaultGraphQlRequest;
import org.springframework.graphql.support.DefaultGraphQlRequest;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.GraphQlResponseError;

View File

@@ -19,10 +19,9 @@ package org.springframework.graphql.test.tester;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.RequestInput;
import org.springframework.graphql.RequestOutput;
import org.springframework.util.Assert;
@@ -48,13 +47,8 @@ final class GraphQlServiceTransport extends AbstractDirectTransport {
}
@Override
protected Mono<RequestOutput> executeInternal(GraphQlRequest request) {
RequestInput requestInput = new RequestInput(
request.getDocument(), request.getOperationName(), request.getVariables(),
idGenerator.generateId().toString(), null);
return this.graphQlService.execute(requestInput);
protected Mono<ExecutionGraphQlResponse> executeInternal(ExecutionGraphQlRequest request) {
return this.graphQlService.execute(request);
}
}

View File

@@ -21,6 +21,8 @@ import java.net.URI;
import reactor.core.publisher.Mono;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.web.WebGraphQlHandler;
import org.springframework.graphql.web.WebInput;
@@ -75,9 +77,9 @@ final class WebGraphQlHandlerTransport extends AbstractDirectTransport {
@Override
protected Mono<WebOutput> executeInternal(GraphQlRequest request) {
return this.graphQlHandler.handleRequest(
new WebInput(this.url, this.headers, request.toMap(), idGenerator.generateId().toString(), null));
protected Mono<ExecutionGraphQlResponse> executeInternal(ExecutionGraphQlRequest request) {
WebInput input = new WebInput(this.url, this.headers, request.toMap(), idGenerator.generateId().toString(), null);
return this.graphQlHandler.handleRequest(input).cast(ExecutionGraphQlResponse.class);
}
}

View File

@@ -48,13 +48,13 @@ public class GraphQlTesterBuilderTests extends GraphQlTesterTestSupport {
GraphQlTester tester = builder.build();
tester.documentName("name").execute();
assertThat(requestInput().getDocument()).isEqualTo(DOCUMENT);
assertThat(request().getDocument()).isEqualTo(DOCUMENT);
// Mutate
tester = tester.mutate().build();
tester.documentName("name").execute();
assertThat(requestInput().getDocument()).isEqualTo(DOCUMENT);
assertThat(request().getDocument()).isEqualTo(DOCUMENT);
}
@Test
@@ -74,7 +74,7 @@ public class GraphQlTesterBuilderTests extends GraphQlTesterTestSupport {
.errors().verify()
.path("me").pathDoesNotExist();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
}

View File

@@ -29,9 +29,9 @@ import graphql.GraphQLError;
import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Mono;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.RequestInput;
import org.springframework.graphql.RequestOutput;
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -46,7 +46,7 @@ public class GraphQlTesterTestSupport {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final ArgumentCaptor<RequestInput> inputCaptor = ArgumentCaptor.forClass(RequestInput.class);
private final ArgumentCaptor<ExecutionGraphQlRequest> requestCaptor = ArgumentCaptor.forClass(ExecutionGraphQlRequest.class);
private final GraphQlService graphQlService = mock(GraphQlService.class);
@@ -63,8 +63,8 @@ public class GraphQlTesterTestSupport {
return this.graphQlTesterBuilder;
}
protected RequestInput requestInput() {
return this.inputCaptor.getValue();
protected ExecutionGraphQlRequest request() {
return this.requestCaptor.getValue();
}
@@ -83,8 +83,8 @@ public class GraphQlTesterTestSupport {
ExecutionInput executionInput = ExecutionInput.newExecutionInput("{}").build();
ExecutionResult result = builder.build();
given(this.graphQlService.execute(this.inputCaptor.capture()))
.willReturn(Mono.just(new RequestOutput(executionInput, result)));
given(this.graphQlService.execute(this.requestCaptor.capture()))
.willReturn(Mono.just(new DefaultExecutionGraphQlResponse(executionInput, result)));
}
private void serialize(String data, ExecutionResultImpl.Builder builder) {

View File

@@ -26,8 +26,8 @@ import graphql.language.SourceLocation;
import org.junit.jupiter.api.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.ExecutionGraphQlRequest;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.RequestInput;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -51,7 +51,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
response.path("me.friends").pathExists().valueExists();
response.path("hero").pathDoesNotExist().valueDoesNotExist();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -69,7 +69,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.as("Path does not even exist")
.hasMessageContaining("No value at JSON path \"$['data']['hero']");
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -88,7 +88,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.as("Extended fields should fail in strict mode")
.hasMessageContaining("Unexpected: name");
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -118,7 +118,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.entity(new ParameterizedTypeReference<Map<String, MovieCharacter>>() {})
.isEqualTo(Collections.singletonMap("me", luke));
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -153,7 +153,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.entityList(new ParameterizedTypeReference<MovieCharacter>() {})
.containsExactly(han, leia);
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -176,13 +176,13 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
response.path("hero").entity(MovieCharacter.class).isEqualTo(MovieCharacter.create("R2-D2"));
RequestInput input = requestInput();
assertThat(input.getDocument()).contains(document);
assertThat(input.getOperationName()).isEqualTo("HeroNameAndFriends");
assertThat(input.getVariables()).hasSize(3);
assertThat(input.getVariables()).containsEntry("episode", "JEDI");
assertThat(input.getVariables()).containsEntry("foo", "bar");
assertThat(input.getVariables()).containsEntry("keyOnly", null);
ExecutionGraphQlRequest request = request();
assertThat(request.getDocument()).contains(document);
assertThat(request.getOperationName()).isEqualTo("HeroNameAndFriends");
assertThat(request.getVariables()).hasSize(3);
assertThat(request.getVariables()).containsEntry("episode", "JEDI");
assertThat(request.getVariables()).containsEntry("foo", "bar");
assertThat(request.getVariables()).containsEntry("keyOnly", null);
}
@Test
@@ -193,7 +193,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
graphQlTester().document(document).executeAndVerify();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -205,7 +205,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
assertThatThrownBy(() -> graphQlTester().document(document).executeAndVerify())
.hasMessageContaining("Response has 1 unexpected error(s)");
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -217,7 +217,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
assertThatThrownBy(() -> graphQlTester().document(document).execute().path("me"))
.hasMessageContaining("Response has 1 unexpected error(s)");
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -236,7 +236,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.verify())
.hasMessageContaining("Response has 1 unexpected error(s) of 2 total.");
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -255,7 +255,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.path("me")
.pathDoesNotExist();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -273,7 +273,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
.verify()
.path("me").pathDoesNotExist();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
@Test
@@ -312,7 +312,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
})
.path("me").pathDoesNotExist();
assertThat(requestInput().getDocument()).contains(document);
assertThat(request().getDocument()).contains(document);
}
}

View File

@@ -34,7 +34,8 @@ import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.DecodingException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.graphql.RequestOutput;
import org.springframework.graphql.ExecutionGraphQlResponse;
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse;
import org.springframework.graphql.support.DocumentSource;
import org.springframework.graphql.web.TestWebSocketClient;
import org.springframework.graphql.web.TestWebSocketConnection;
@@ -210,11 +211,11 @@ public class WebGraphQlTesterBuilderTests {
private WebInput webInput;
private final Map<String, RequestOutput> responses = new HashMap<>();
private final Map<String, ExecutionGraphQlResponse> responses = new HashMap<>();
public WebBuilderSetup() {
RequestOutput defaultResponse = new RequestOutput(
ExecutionGraphQlResponse defaultResponse = new DefaultExecutionGraphQlResponse(
ExecutionInput.newExecutionInput().query(DOCUMENT).build(),
ExecutionResultImpl.newExecutionResult().build());
@@ -227,11 +228,11 @@ public class WebGraphQlTesterBuilderTests {
}
protected WebGraphQlHandler webGraphQlHandler() {
return WebGraphQlHandler.builder(requestInput -> {
String document = requestInput.getDocument();
RequestOutput output = this.responses.get(document);
Assert.notNull(output, "Unexpected request: " + document);
return Mono.just(output);
return WebGraphQlHandler.builder(request -> {
String document = request.getDocument();
ExecutionGraphQlResponse response = this.responses.get(document);
Assert.notNull(response, "Unexpected request: " + document);
return Mono.just(response);
})
.interceptor((input, chain) -> {
this.webInput = input;
@@ -243,7 +244,7 @@ public class WebGraphQlTesterBuilderTests {
@Override
public void setMockResponse(String document, ExecutionResult result) {
ExecutionInput executionInput = ExecutionInput.newExecutionInput().query(document).build();
this.responses.put(document, new RequestOutput(executionInput, result));
this.responses.put(document, new DefaultExecutionGraphQlResponse(executionInput, result));
}
@Override