Skip to content

Commit

Permalink
Adapt to GraphQL over HTTP spec changes
Browse files Browse the repository at this point in the history
As of graphql/graphql-over-http#215, the official media type for GraphQL
HTTP responses is now `"application/graphql-response+json"` instead of
`"application/graphql+json"`. The latter is now deprecated and support
will be removed in the future.

This commit now favors the new media type.
HTTP Clients are still supposed to send requests with the
`"application/json"` content type.

Closes gh-563
  • Loading branch information
bclozel committed Dec 5, 2022
1 parent eb9b1f3 commit 573e899
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 13 deletions.
Expand Up @@ -44,6 +44,10 @@ final class HttpGraphQlTransport implements GraphQlTransport {
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE =
new ParameterizedTypeReference<Map<String, Object>>() {};

// To be removed in favor of Framework's MediaType.APPLICATION_GRAPHQL_RESPONSE
private static final MediaType APPLICATION_GRAPHQL_RESPONSE =
new MediaType("application", "graphql-response+json");


private final WebClient webClient;

Expand All @@ -65,10 +69,11 @@ private static MediaType initContentType(WebClient webClient) {


@Override
@SuppressWarnings("removal")
public Mono<GraphQlResponse> execute(GraphQlRequest request) {
return this.webClient.post()
.contentType(this.contentType)
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL)
.accept(MediaType.APPLICATION_JSON, APPLICATION_GRAPHQL_RESPONSE, MediaType.APPLICATION_GRAPHQL)
.bodyValue(request.toMap())
.retrieve()
.bodyToMono(MAP_TYPE)
Expand Down
Expand Up @@ -43,11 +43,16 @@ public class GraphQlHttpHandler {

private static final Log logger = LogFactory.getLog(GraphQlHttpHandler.class);

// To be removed in favor of Framework's MediaType.APPLICATION_GRAPHQL_RESPONSE
private static final MediaType APPLICATION_GRAPHQL_RESPONSE =
new MediaType("application", "graphql-response+json");

private static final ParameterizedTypeReference<Map<String, Object>> MAP_PARAMETERIZED_TYPE_REF =
new ParameterizedTypeReference<Map<String, Object>>() {};

@SuppressWarnings("removal")
private static final List<MediaType> SUPPORTED_MEDIA_TYPES =
Arrays.asList(MediaType.APPLICATION_GRAPHQL, MediaType.APPLICATION_JSON);
Arrays.asList(APPLICATION_GRAPHQL_RESPONSE, MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL);

private final WebGraphQlHandler graphQlHandler;

Expand Down
Expand Up @@ -55,8 +55,13 @@ public class GraphQlHttpHandler {
private static final ParameterizedTypeReference<Map<String, Object>> MAP_PARAMETERIZED_TYPE_REF =
new ParameterizedTypeReference<Map<String, Object>>() {};

// To be removed in favor of Framework's MediaType.APPLICATION_GRAPHQL_RESPONSE
private static final MediaType APPLICATION_GRAPHQL_RESPONSE =
new MediaType("application", "graphql-response+json");

@SuppressWarnings("removal")
private static final List<MediaType> SUPPORTED_MEDIA_TYPES =
Arrays.asList(MediaType.APPLICATION_GRAPHQL, MediaType.APPLICATION_JSON);
Arrays.asList(APPLICATION_GRAPHQL_RESPONSE, MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL);

private final IdGenerator idGenerator = new AlternativeJdkIdGenerator();

Expand Down
Expand Up @@ -189,13 +189,14 @@ void contentTypeDefault() {

@Test
void contentTypeOverride() {
MediaType testMediaType = new MediaType("application", "graphql-request+json");

HttpBuilderSetup setup = new HttpBuilderSetup();
setup.initBuilder().header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_GRAPHQL_VALUE).build()
setup.initBuilder().header(HttpHeaders.CONTENT_TYPE, "application/graphql-request+json").build()
.document(DOCUMENT).execute().block(TIMEOUT);

WebGraphQlRequest request = setup.getActualRequest();
assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL);
assertThat(request.getHeaders().getContentType()).isEqualTo(testMediaType);

}

Expand Down
Expand Up @@ -64,12 +64,12 @@ void shouldProduceApplicationJsonByDefault() {
@Test
void shouldProduceApplicationGraphQl() {
MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/")
.contentType(MediaType.APPLICATION_GRAPHQL).accept(MediaType.APPLICATION_GRAPHQL).build();
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build();

MockServerHttpResponse httpResponse = handleRequest(
httpRequest, this.greetingHandler, Collections.singletonMap("query", "{greeting}"));

assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL);
assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE);
}

@Test
Expand All @@ -90,7 +90,8 @@ void locale() {
.toHttpHandlerWebFlux();

MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/")
.contentType(MediaType.APPLICATION_GRAPHQL).accept(MediaType.APPLICATION_GRAPHQL).acceptLanguageAsLocales(Locale.FRENCH).build();
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE)
.acceptLanguageAsLocales(Locale.FRENCH).build();

MockServerHttpResponse httpResponse = handleRequest(
httpRequest, handler, Collections.singletonMap("query", "{greeting}"));
Expand All @@ -106,7 +107,7 @@ void shouldSetExecutionId() {
.toHttpHandlerWebFlux();

MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/")
.contentType(MediaType.APPLICATION_GRAPHQL).accept(MediaType.APPLICATION_GRAPHQL).build();
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build();

MockServerHttpResponse httpResponse = handleRequest(
httpRequest, handler, Collections.singletonMap("query", "{showId}"));
Expand Down
Expand Up @@ -64,9 +64,9 @@ void shouldProduceApplicationJsonByDefault() throws Exception {

@Test
void shouldProduceApplicationGraphQl() throws Exception {
MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_VALUE);
MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE);
MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler);
assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_VALUE);
assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE);
}

@Test
Expand All @@ -81,7 +81,7 @@ void locale() throws Exception {
GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { greeting: String }")
.queryFetcher("greeting", (env) -> "Hello in " + env.getLocale())
.toHttpHandler();
MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_VALUE);
MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE);
LocaleContextHolder.setLocale(Locale.FRENCH);

try {
Expand All @@ -101,7 +101,7 @@ void shouldSetExecutionId() throws Exception {
.queryFetcher("showId", (env) -> env.getExecutionId().toString())
.toHttpHandler();

MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ showId }\"}", MediaType.APPLICATION_GRAPHQL_VALUE);
MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ showId }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE);

MockHttpServletResponse servletResponse = handleRequest(servletRequest, handler);
DocumentContext document = JsonPath.parse(servletResponse.getContentAsString());
Expand Down

0 comments on commit 573e899

Please sign in to comment.