diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java index 1d528460..841b19cf 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webflux/AbstractGraphQlHttpHandler.java @@ -22,15 +22,18 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.support.SerializableGraphQlRequest; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.UnsupportedMediaTypeStatusException; /** * Abstract class for GraphQL Handler implementations using the HTTP transport. * * @author Brian Clozel + * @author Rossen Stoyanchev */ class AbstractGraphQlHttpHandler { @@ -51,9 +54,26 @@ class AbstractGraphQlHttpHandler { return this.codecDelegate.decode(serverRequest.bodyToFlux(DataBuffer.class), contentType); } else { - return serverRequest.bodyToMono(SerializableGraphQlRequest.class); + return serverRequest.bodyToMono(SerializableGraphQlRequest.class) + .onErrorResume( + UnsupportedMediaTypeStatusException.class, + (ex) -> applyApplicationGraphQlFallback(ex, serverRequest)); } } + private static Mono applyApplicationGraphQlFallback( + UnsupportedMediaTypeStatusException ex, ServerRequest request) { + + // Spec requires application/json but some clients still use application/graphql + return "application/graphql".equals(request.headers().firstHeader(HttpHeaders.CONTENT_TYPE)) ? + ServerRequest.from(request) + .headers((headers) -> headers.setContentType(MediaType.APPLICATION_JSON)) + .body(request.bodyToFlux(DataBuffer.class)) + .build() + .bodyToMono(SerializableGraphQlRequest.class) + .log() : + Mono.error(ex); + } + } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java index bb68c712..4bd725b8 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/server/webmvc/AbstractGraphQlHttpHandler.java @@ -27,6 +27,7 @@ import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.support.SerializableGraphQlRequest; import org.springframework.http.HttpCookie; +import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpRequest; @@ -81,10 +82,16 @@ abstract class AbstractGraphQlHttpHandler { return (GraphQlRequest) this.messageConverter.read(SerializableGraphQlRequest.class, new ServletServerHttpRequest(request.servletRequest())); } - throw new HttpMediaTypeNotSupportedException(contentType, this.messageConverter.getSupportedMediaTypes(), request.method()); + throw new HttpMediaTypeNotSupportedException( + contentType, this.messageConverter.getSupportedMediaTypes(), request.method()); } else { - return request.body(SerializableGraphQlRequest.class); + try { + return request.body(SerializableGraphQlRequest.class); + } + catch (HttpMediaTypeNotSupportedException ex) { + return applyApplicationGraphQlFallback(request, ex); + } } } catch (IOException ex) { @@ -92,4 +99,23 @@ abstract class AbstractGraphQlHttpHandler { } } + private static SerializableGraphQlRequest applyApplicationGraphQlFallback( + ServerRequest request, HttpMediaTypeNotSupportedException ex) throws HttpMediaTypeNotSupportedException { + + // Spec requires application/json but some clients still use application/graphql + if ("application/graphql".equals(request.headers().firstHeader(HttpHeaders.CONTENT_TYPE))) { + try { + request = ServerRequest.from(request) + .headers((headers) -> headers.setContentType(MediaType.APPLICATION_JSON)) + .body(request.body(byte[].class)) + .build(); + return request.body(SerializableGraphQlRequest.class); + } + catch (Throwable ex2) { + // ignore + } + } + throw ex; + } + } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java b/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java index 3fe4089a..768ac766 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java @@ -26,28 +26,29 @@ import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import org.springframework.core.codec.DataBufferEncoder; +import org.springframework.core.io.buffer.DefaultDataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.GraphQlSetup; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.support.SerializableGraphQlRequest; import org.springframework.http.MediaType; import org.springframework.http.codec.CodecConfigurer; +import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpResponse; -import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; -import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; @@ -57,72 +58,101 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class GraphQlHttpHandlerTests { - private final GraphQlHttpHandler greetingHandler = GraphQlSetup.schemaContent("type Query { greeting: String }") - .queryFetcher("greeting", (env) -> "Hello").toHttpHandlerWebFlux(); + private static final List> MESSAGE_READERS = + List.of(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder())); + + private final GraphQlHttpHandler greetingHandler = + GraphQlSetup.schemaContent("type Query { greeting: String }") + .queryFetcher("greeting", (env) -> "Hello") + .toHttpHandlerWebFlux(); @Test - void shouldProduceApplicationJsonByDefault() { - MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.ALL).build(); - + void shouldProduceApplicationJsonByDefault() throws Exception { String document = "{greeting}"; - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest(document)); + MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.ALL) + .body(initRequestBody(document)); - assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + MockServerHttpResponse response = handleRequest(httpRequest, this.greetingHandler); + + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + StepVerifier.create(response.getBodyAsString()) + .expectNext("{\"data\":{\"greeting\":\"Hello\"}}") + .verifyComplete(); } @Test - void shouldProduceApplicationGraphQl() { + void shouldSupportApplicationGraphQl() throws Exception { + String document = "{greeting}"; MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build(); + .contentType(MediaType.parseMediaType("application/graphql")) + .accept(MediaType.ALL) + .body(initRequestBody(document)); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest("{greeting}")); + MockServerHttpResponse response = handleRequest(httpRequest, this.greetingHandler); + + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + StepVerifier.create(response.getBodyAsString()) + .expectNext("{\"data\":{\"greeting\":\"Hello\"}}") + .verifyComplete(); + } + + @Test + void shouldProduceApplicationGraphQl() throws Exception { + MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .body(initRequestBody("{greeting}")); + + MockServerHttpResponse httpResponse = handleRequest(httpRequest, this.greetingHandler); assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE); } @Test - void shouldProduceApplicationJson() { + void shouldProduceApplicationJson() throws Exception { MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(initRequestBody("{greeting}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest("{greeting}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, this.greetingHandler); assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); } @Test - void locale() { + void locale() throws Exception { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello in " + env.getLocale()) .toHttpHandlerWebFlux(); MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) - .acceptLanguageAsLocales(Locale.FRENCH).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .acceptLanguageAsLocales(Locale.FRENCH) + .body(initRequestBody("{greeting}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, handler, initRequest("{greeting}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, handler); assertThat(httpResponse.getBodyAsString().block()) .isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); } @Test - void shouldSetExecutionId() { + void shouldSetExecutionId() throws Exception { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { showId: String }") .queryFetcher("showId", (env) -> env.getExecutionId().toString()) .toHttpHandlerWebFlux(); MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .body(initRequestBody("{showId}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, handler, initRequest("{showId}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, handler); DocumentContext document = JsonPath.parse(httpResponse.getBodyAsString().block()); String id = document.read("data.showId", String.class); @@ -134,24 +164,25 @@ public class GraphQlHttpHandlerTests { WebGraphQlHandler webGraphQlHandler = GraphQlSetup.schemaContent("type Query { showId: String }") .queryFetcher("showId", (env) -> env.getExecutionId().toString()) .toWebGraphQlHandler(); + ObjectMapper mapper = new ObjectMapper(); CodecConfigurer configurer = ServerCodecConfigurer.create(); configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper)); configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper)); - GraphQlHttpHandler httpHandler = new GraphQlHttpHandler(webGraphQlHandler, configurer); + + byte[] bytes = "{\"query\": \"{showId}\"}".getBytes(StandardCharsets.UTF_8); + Flux body = Flux.just(DefaultDataBufferFactory.sharedInstance.wrap(bytes)); MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .body(body); MockServerWebExchange exchange = MockServerWebExchange.from(httpRequest); - MockServerRequest serverRequest = MockServerRequest.builder() - .exchange(exchange) - .uri(((ServerWebExchange) exchange).getRequest().getURI()) - .method(((ServerWebExchange) exchange).getRequest().getMethod()) - .headers(((ServerWebExchange) exchange).getRequest().getHeaders()) - .body(Flux.just(DefaultDataBufferFactory.sharedInstance.wrap("{\"query\":\"{showId}\"}".getBytes(StandardCharsets.UTF_8)))); + ServerRequest request = ServerRequest.create(exchange, configurer.getReaders()); - httpHandler.handleRequest(serverRequest) + new GraphQlHttpHandler(webGraphQlHandler, configurer) + .handleRequest(request) .flatMap(response -> response.writeTo(exchange, new EmptyContext())) .block(); @@ -160,23 +191,15 @@ public class GraphQlHttpHandlerTests { assertThat(id).isEqualTo(httpRequest.getId()); } - private static SerializableGraphQlRequest initRequest(String document) { + private static String initRequestBody(String document) throws Exception { SerializableGraphQlRequest request = new SerializableGraphQlRequest(); request.setQuery(document); - return request; + return new ObjectMapper().writeValueAsString(request); } - private MockServerHttpResponse handleRequest( - MockServerHttpRequest httpRequest, GraphQlHttpHandler handler, GraphQlRequest body) { - + private MockServerHttpResponse handleRequest(MockServerHttpRequest httpRequest, GraphQlHttpHandler handler) { MockServerWebExchange exchange = MockServerWebExchange.from(httpRequest); - - MockServerRequest serverRequest = MockServerRequest.builder() - .exchange(exchange) - .uri(((ServerWebExchange) exchange).getRequest().getURI()) - .method(((ServerWebExchange) exchange).getRequest().getMethod()) - .headers(((ServerWebExchange) exchange).getRequest().getHeaders()) - .body(Mono.just(body)); + ServerRequest serverRequest = ServerRequest.create(exchange, MESSAGE_READERS); handler.handleRequest(serverRequest) .flatMap(response -> response.writeTo(exchange, new DefaultContext())) diff --git a/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java b/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java index dac02207..76e05957 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java @@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.UUID; import com.jayway.jsonpath.DocumentContext; @@ -29,11 +30,14 @@ import graphql.execution.preparsed.persisted.ApolloPersistedQuerySupport; import graphql.execution.preparsed.persisted.InMemoryPersistedQueryCache; import jakarta.servlet.ServletException; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.graphql.GraphQlSetup; import org.springframework.graphql.server.WebGraphQlHandler; +import org.springframework.graphql.server.support.SerializableGraphQlRequest; import org.springframework.http.MediaType; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.mock.web.MockHttpServletRequest; @@ -53,28 +57,39 @@ import static org.assertj.core.api.Assertions.assertThatNoException; public class GraphQlHttpHandlerTests { private static final List> MESSAGE_READERS = - Collections.singletonList(new MappingJackson2HttpMessageConverter()); + List.of(new MappingJackson2HttpMessageConverter(), new ByteArrayHttpMessageConverter()); private final GraphQlHttpHandler greetingHandler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello").toHttpHandler(); + @Test void shouldProduceApplicationJsonByDefault() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", "*/*"); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); - assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE); + MockHttpServletRequest request = createServletRequest("{ greeting }", "*/*"); + MockHttpServletResponse response = handleRequest(request, this.greetingHandler); + assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"greeting\":\"Hello\"}}"); + } + + @Test + void shouldSupportApplicationGraphQl() throws Exception { + MockHttpServletRequest request = createServletRequest("{ greeting }", "*/*"); + request.setContentType("application/graphql"); + + MockHttpServletResponse response = handleRequest(request, this.greetingHandler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"greeting\":\"Hello\"}}"); } @Test void shouldProduceApplicationGraphQl() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); - assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletRequest request = createServletRequest("{ greeting }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletResponse response = handleRequest(request, this.greetingHandler); + assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); } @Test void shouldProduceApplicationJson() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", "application/json"); + MockHttpServletRequest servletRequest = createServletRequest("{ greeting }", "application/json"); MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); assertThat(servletResponse.getContentType()).isEqualTo("application/json"); } @@ -84,14 +99,15 @@ public class GraphQlHttpHandlerTests { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello in " + env.getLocale()) .toHttpHandler(); - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + + MockHttpServletRequest request = createServletRequest( + "{ greeting }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + LocaleContextHolder.setLocale(Locale.FRENCH); try { - MockHttpServletResponse servletResponse = handleRequest(servletRequest, handler); - - assertThat(servletResponse.getContentAsString()) - .isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); + MockHttpServletResponse response = handleRequest(request, handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); } finally { LocaleContextHolder.resetLocaleContext(); @@ -104,10 +120,12 @@ public class GraphQlHttpHandlerTests { .queryFetcher("showId", (env) -> env.getExecutionId().toString()) .toHttpHandler(); - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ showId }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletRequest request = createServletRequest( + "{ showId }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, handler); - DocumentContext document = JsonPath.parse(servletResponse.getContentAsString()); + MockHttpServletResponse response = handleRequest(request, handler); + + DocumentContext document = JsonPath.parse(response.getContentAsString()); String id = document.read("data.showId", String.class); assertThatNoException().isThrownBy(() -> UUID.fromString(id)); } @@ -116,8 +134,9 @@ public class GraphQlHttpHandlerTests { void shouldUseCustomMessageConverter() throws Exception { WebGraphQlHandler webGraphQlHandler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello").toWebGraphQlHandler(); + GraphQlHttpHandler handler = new GraphQlHttpHandler(webGraphQlHandler, new MappingJackson2HttpMessageConverter()); - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletRequest servletRequest = createServletRequest("{ greeting }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList()); ServerResponse response = handler.handleRequest(request); @@ -141,44 +160,44 @@ public class GraphQlHttpHandlerTests { .configureGraphQl(builder -> builder.preparsedDocumentProvider(documentProvider)) .toHttpHandler(); - String document = """ - { - "query" : "{__typename}", - "extensions": { - "persistedQuery": { - "version":1, - "sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" - } - } - }"""; + SerializableGraphQlRequest request = new SerializableGraphQlRequest(); + request.setQuery("{__typename}"); + request.setExtensions(Map.of("persistedQuery", Map.of( + "version", "1", + "sha256Hash", "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"))); - MockHttpServletResponse servletResponse = handleRequest(createServletRequest(document, "*/*"), handler); - assertThat(servletResponse.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); + MockHttpServletResponse response = handleRequest(createServletRequest(request, "*/*"), handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); - document = """ - { - "extensions":{ - "persistedQuery":{ - "version":1, - "sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" - } - } - }"""; + request = new SerializableGraphQlRequest(); + request.setQuery("{__typename}"); + request.setExtensions(Map.of("persistedQuery", Map.of( + "version", "1", + "sha256Hash", "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"))); - servletResponse = handleRequest(createServletRequest(document, "*/*"), handler); - assertThat(servletResponse.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); + response = handleRequest(createServletRequest(request, "*/*"), handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); } + private MockHttpServletRequest createServletRequest(String document, String accept) throws Exception { + SerializableGraphQlRequest request = new SerializableGraphQlRequest(); + request.setQuery(document); + return createServletRequest(request, accept); + } - private MockHttpServletRequest createServletRequest(String query, String accept) { + private MockHttpServletRequest createServletRequest(SerializableGraphQlRequest request, String accept) throws Exception { MockHttpServletRequest servletRequest = new MockHttpServletRequest("POST", "/"); servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - servletRequest.setContent(query.getBytes(StandardCharsets.UTF_8)); + servletRequest.setContent(initRequestBody(request)); servletRequest.addHeader("Accept", accept); servletRequest.setAsyncSupported(true); return servletRequest; } + private static byte[] initRequestBody(SerializableGraphQlRequest request) throws Exception { + return new ObjectMapper().writeValueAsString(request).getBytes(StandardCharsets.UTF_8); + } + private MockHttpServletResponse handleRequest( MockHttpServletRequest servletRequest, GraphQlHttpHandler handler) throws ServletException, IOException { @@ -200,7 +219,6 @@ public class GraphQlHttpHandlerTests { public List> messageConverters() { return MESSAGE_READERS; } - } }