Refactor MapGraphQlResponse

MapGraphQlResponse is a simple wrapper around the response map exposing
it as GraphQlResponse. It is now package private and made accessible
through a static factory method on GraphQlTransport.

See gh-10
This commit is contained in:
rstoyanchev
2022-03-17 19:56:31 +00:00
parent 3c30376cba
commit 96135183f5
10 changed files with 34 additions and 54 deletions

View File

@@ -26,7 +26,6 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.client.GraphQlTransport;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.Assert;
@@ -67,7 +66,7 @@ final class WebTestClientTransport implements GraphQlTransport {
.getResponseBody();
responseMap = (responseMap != null ? responseMap : Collections.emptyMap());
GraphQlResponse response = MapGraphQlResponse.forResponse(responseMap);
GraphQlResponse response = GraphQlTransport.wrapResponseMap(responseMap);
return Mono.just(response);
}

View File

@@ -31,7 +31,6 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;

View File

@@ -16,6 +16,8 @@
package org.springframework.graphql.client;
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -57,4 +59,12 @@ public interface GraphQlTransport {
*/
Flux<GraphQlResponse> executeSubscription(GraphQlRequest request);
/**
* Wrap the given response map and expose it as a {@link GraphQlResponse}.
*/
static GraphQlResponse wrapResponseMap(Map<String, Object> map) {
return new MapGraphQlResponse(map);
}
}

View File

@@ -24,7 +24,6 @@ import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
@@ -61,7 +60,7 @@ final class HttpGraphQlTransport implements GraphQlTransport {
.bodyValue(request.toMap())
.retrieve()
.bodyToMono(MAP_TYPE)
.map(MapGraphQlResponse::forResponse);
.map(GraphQlTransport::wrapResponseMap);
}
@Override

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.graphql.support;
package org.springframework.graphql.client;
import java.util.Collections;
import java.util.List;
@@ -31,7 +31,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Implementation of {@link GraphQLError} backed by a {@link Map}.
* {@link GraphQLError} that wraps a deserialized the GraphQL response map.
*
* @author Rossen Stoyanchev
* @since 1.0.0

View File

@@ -14,14 +14,13 @@
* limitations under the License.
*/
package org.springframework.graphql.support;
package org.springframework.graphql.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import graphql.ExecutionResult;
import graphql.GraphQLError;
import org.springframework.graphql.GraphQlResponse;
@@ -31,12 +30,12 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link GraphQlResponse} for client use that wraps the GraphQL response map.
* {@link GraphQlResponse} that wraps a deserialized the GraphQL response map.
*
* @author Rossen Stoyanchev
* @since 1.0.0
*/
public class MapGraphQlResponse implements GraphQlResponse {
class MapGraphQlResponse implements GraphQlResponse {
/**
* Returned from {@link #getFieldValue(List)} to indicate a value does not exist.
@@ -49,7 +48,7 @@ public class MapGraphQlResponse implements GraphQlResponse {
private final List<GraphQLError> errors;
protected MapGraphQlResponse(Map<String, Object> responseMap) {
MapGraphQlResponse(Map<String, Object> responseMap) {
Assert.notNull(responseMap, "'responseMap' is required");
this.responseMap = responseMap;
this.errors = wrapErrors(responseMap);
@@ -218,29 +217,4 @@ public class MapGraphQlResponse implements GraphQlResponse {
return this.responseMap.toString();
}
/**
* Create an instance from an {@code ExecutionResult} serialized to map via
* {@link ExecutionResult#toSpecification()}.
*/
public static MapGraphQlResponse forResponse(Map<String, Object> map) {
return new MapGraphQlResponse(map);
}
/**
* Create an {@code ExecutionResult} with a "data" key that returns the
* given map.
*/
public static MapGraphQlResponse forDataOnly(@Nullable Map<String, Object> map) {
return new MapGraphQlResponse(Collections.singletonMap("data", map));
}
/**
* Create an {@code ExecutionResult} with an "errors" key that returns the
* given serialized errors.
*/
public static MapGraphQlResponse forErrorsOnly(List<Map<String, Object>> errors) {
return new MapGraphQlResponse(Collections.singletonMap("errors", errors));
}
}

View File

@@ -34,7 +34,6 @@ import reactor.core.publisher.Sinks;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.graphql.web.support.GraphQlMessage;
import org.springframework.graphql.web.support.GraphQlMessageType;
import org.springframework.http.HttpHeaders;
@@ -477,7 +476,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}
Map<String, Object> responseMap = message.getPayload();
GraphQlResponse graphQlResponse = MapGraphQlResponse.forResponse(responseMap);
GraphQlResponse graphQlResponse = GraphQlTransport.wrapResponseMap(responseMap);
Sinks.EmitResult emitResult = (responseState != null ?
responseState.sink().tryEmitValue(graphQlResponse) :
@@ -508,7 +507,7 @@ final class WebSocketGraphQlTransport implements GraphQlTransport {
}
List<Map<String, Object>> errorList = message.getPayload();
GraphQlResponse response = MapGraphQlResponse.forErrorsOnly(errorList);
GraphQlResponse response = GraphQlTransport.wrapResponseMap(Collections.singletonMap("errors", errorList));
Sinks.EmitResult emitResult;
if (responseState != null) {

View File

@@ -29,7 +29,6 @@ import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Mono;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
@@ -96,7 +95,7 @@ public class GraphQlClientTestSupport {
Map<String, Object> responseMap = executionResult.toSpecification();
when(this.transport.execute(eq(request)))
.thenReturn(Mono.just(MapGraphQlResponse.forResponse(responseMap)));
.thenReturn(Mono.just(GraphQlTransport.wrapResponseMap(responseMap)));
}
@SuppressWarnings("unchecked")

View File

@@ -14,9 +14,10 @@
* limitations under the License.
*/
package org.springframework.graphql.support;
package org.springframework.graphql.client;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -32,7 +33,6 @@ import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.graphql.support.MapGraphQlResponse.NO_VALUE;
/**
@@ -81,12 +81,12 @@ public class MapGraphQlResponseTests {
// null "data"
testFieldValue("", "null", null);
testFieldValue("me", "null", NO_VALUE);
testFieldValue("me", "null", MapGraphQlResponse.NO_VALUE);
// no such key or index
testFieldValue("me", "{}", NO_VALUE); // "data" not null but no such key
testFieldValue("me.friends", "{\"me\":{}}", NO_VALUE);
testFieldValue("me.friends[0]", "{\"me\": {\"friends\": []}}", NO_VALUE);
testFieldValue("me", "{}", MapGraphQlResponse.NO_VALUE); // "data" not null but no such key
testFieldValue("me.friends", "{\"me\":{}}", MapGraphQlResponse.NO_VALUE);
testFieldValue("me.friends[0]", "{\"me\": {\"friends\": []}}", MapGraphQlResponse.NO_VALUE);
// nest within map or list
testFieldValue("me.name", "{\"me\":{\"name\":\"Luke\"}}", "Luke");
@@ -97,7 +97,7 @@ public class MapGraphQlResponseTests {
private static void testFieldValue(String path, String json, @Nullable Object expected) throws IOException {
List<Object> parsedPath = MapGraphQlResponse.parseFieldPath(path);
Map<String, Object> map = mapper.readValue(json, Map.class);
MapGraphQlResponse response = MapGraphQlResponse.forDataOnly(map);
MapGraphQlResponse response = new MapGraphQlResponse(Collections.singletonMap("data", map));
Object value = response.getFieldValue(parsedPath);
if (expected != null) {
assertThat(value).isEqualTo(expected);
@@ -119,7 +119,7 @@ public class MapGraphQlResponseTests {
private static void testFieldValueInvalidPath(String path, String json) throws IOException {
List<Object> parsedPath = MapGraphQlResponse.parseFieldPath(path);
Map<String, Object> map = mapper.readValue(json, Map.class);
MapGraphQlResponse response = MapGraphQlResponse.forDataOnly(map);
MapGraphQlResponse response = new MapGraphQlResponse(Collections.singletonMap("data", map));
assertThatIllegalArgumentException().isThrownBy(() -> response.getFieldValue(parsedPath))
.withMessage("Invalid path " + parsedPath + ", data: " + map);
@@ -139,7 +139,7 @@ public class MapGraphQlResponseTests {
Stream.of(error0, error1, error2, error3)
.map(GraphQLError::toSpecification).collect(Collectors.toList());
MapGraphQlResponse response = MapGraphQlResponse.forErrorsOnly(errorList);
MapGraphQlResponse response = new MapGraphQlResponse(Collections.singletonMap("errors", errorList));
List<GraphQLError> errors = response.getFieldErrors(path);
assertThat(errors).containsExactly(error1, error2, error3);

View File

@@ -34,7 +34,6 @@ import reactor.test.StepVerifier;
import org.springframework.graphql.GraphQlRequest;
import org.springframework.graphql.GraphQlResponse;
import org.springframework.graphql.support.MapGraphQlResponse;
import org.springframework.graphql.web.TestWebSocketClient;
import org.springframework.graphql.web.TestWebSocketConnection;
import org.springframework.graphql.web.support.GraphQlMessage;
@@ -70,9 +69,11 @@ public class MockWebSocketGraphQlTransportTests {
private final WebSocketGraphQlTransport transport = createTransport(this.webSocketClient);
private final GraphQlResponse response1 = MapGraphQlResponse.forDataOnly(Collections.singletonMap("key1", "value1"));
private final GraphQlResponse response1 = GraphQlTransport.wrapResponseMap(
Collections.singletonMap("data", Collections.singletonMap("key1", "value1")));
private final GraphQlResponse response2 = MapGraphQlResponse.forDataOnly(Collections.singletonMap("key2", "value2"));
private final GraphQlResponse response2 = GraphQlTransport.wrapResponseMap(
Collections.singletonMap("data", Collections.singletonMap("key2", "value2")));
@Test