diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java index 4649192258..05f6eaadcf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java @@ -55,6 +55,7 @@ import org.springframework.graphql.server.webflux.SchemaHandler; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.reactive.HandlerMapping; @@ -112,6 +113,7 @@ public class GraphQlWebFluxAutoConfiguration { RouterFunctions.Builder builder = RouterFunctions.route(); builder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest); builder.route(GraphQlRequestPredicates.graphQlSse(path), sseHandler::handleRequest); + builder.POST(path, this::unsupportedMediaType); builder.GET(path, this::onlyAllowPost); if (properties.getGraphiql().isEnabled()) { GraphiQlHandler graphQlHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath()); @@ -124,6 +126,14 @@ public class GraphQlWebFluxAutoConfiguration { return builder.build(); } + private Mono unsupportedMediaType(ServerRequest request) { + return ServerResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).headers(this::acceptJson).build(); + } + + private void acceptJson(HttpHeaders headers) { + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + } + private Mono onlyAllowPost(ServerRequest request) { return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java index 0c44464042..c36823761e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java @@ -117,6 +117,7 @@ public class GraphQlWebMvcAutoConfiguration { RouterFunctions.Builder builder = RouterFunctions.route(); builder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest); builder.route(GraphQlRequestPredicates.graphQlSse(path), sseHandler::handleRequest); + builder.POST(path, this::unsupportedMediaType); builder.GET(path, this::onlyAllowPost); if (properties.getGraphiql().isEnabled()) { GraphiQlHandler graphiQLHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath()); @@ -129,6 +130,14 @@ public class GraphQlWebMvcAutoConfiguration { return builder.build(); } + private ServerResponse unsupportedMediaType(ServerRequest request) { + return ServerResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).headers(this::acceptJson).build(); + } + + private void acceptJson(HttpHeaders headers) { + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + } + private ServerResponse onlyAllowPost(ServerRequest request) { return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfigurationTests.java index bf4dc6695d..51978cc79f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfigurationTests.java @@ -119,7 +119,23 @@ class GraphQlWebFluxAutoConfigurationTests { } @Test - void httpGetQueryShouldBeSupported() { + void unsupportedContentTypeShouldBeRejected() { + testWithWebClient((client) -> { + String query = "{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }"; + client.post() + .uri("/graphql") + .contentType(MediaType.TEXT_PLAIN) + .bodyValue("{ \"query\": \"" + query + "\"}") + .exchange() + .expectStatus() + .isEqualTo(HttpStatus.UNSUPPORTED_MEDIA_TYPE) + .expectHeader() + .valueEquals("Accept", "application/json"); + }); + } + + @Test + void httpGetQueryShouldBeRejected() { testWithWebClient((client) -> { String query = "{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }"; client.get() diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java index 260f122c14..9f6a455ab0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java @@ -111,7 +111,20 @@ class GraphQlWebMvcAutoConfigurationTests { } @Test - void httpGetQueryShouldBeSupported() { + void unsupportedContentTypeShouldBeRejected() { + withMockMvc((mvc) -> { + String query = "{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }"; + assertThat(mvc.post() + .uri("/graphql") + .content("{\"query\": \"" + query + "\"}") + .contentType(MediaType.TEXT_PLAIN)).hasStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) + .headers() + .hasValue("Accept", "application/json"); + }); + } + + @Test + void httpGetQueryShouldBeRejected() { withMockMvc((mvc) -> { String query = "{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }"; assertThat(mvc.get().uri("/graphql?query={query}", "{\"query\": \"" + query + "\"}"))