Skip to content

Commit 9178075

Browse files
committed
Return 405 "Allow:POST" for HTTP GET queries
See gh-70
1 parent e3be107 commit 9178075

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebFluxAutoConfiguration.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import org.springframework.graphql.web.WebInterceptor;
4343
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
4444
import org.springframework.graphql.web.webflux.GraphQlWebSocketHandler;
45+
import org.springframework.http.HttpMethod;
46+
import org.springframework.http.HttpStatus;
4547
import org.springframework.http.MediaType;
4648
import org.springframework.http.codec.ServerCodecConfigurer;
4749
import org.springframework.web.reactive.HandlerMapping;
@@ -87,18 +89,27 @@ public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler
8789
@Bean
8890
public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
8991
GraphQlProperties properties, ResourceLoader resourceLoader) {
92+
9093
String graphQLPath = properties.getPath();
9194
if (logger.isInfoEnabled()) {
9295
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
9396
}
9497
// @formatter:off
9598
RouterFunctions.Builder builder = RouterFunctions.route()
96-
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)), handler::handleRequest);
99+
.GET(graphQLPath, request ->
100+
ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED)
101+
.headers(headers -> headers.setAllow(Collections.singleton(HttpMethod.POST)))
102+
.build())
103+
.POST(graphQLPath,
104+
accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)),
105+
handler::handleRequest);
106+
97107
if (properties.getGraphiql().isEnabled()) {
98108
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
99109
GraphiQlWebFluxHandler graphiQlHandler = new GraphiQlWebFluxHandler(graphQLPath, resource);
100110
builder = builder.GET(properties.getGraphiql().getPath(), graphiQlHandler::showGraphiQlPage);
101111
}
112+
102113
if (properties.getSchema().getPrinter().isEnabled()) {
103114
SchemaPrinter printer = new SchemaPrinter();
104115
builder = builder.GET(graphQLPath + properties.getSchema().getPrinter().getPath(),

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebMvcAutoConfiguration.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
import org.springframework.graphql.web.WebInterceptor;
4848
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
4949
import org.springframework.graphql.web.webmvc.GraphQlWebSocketHandler;
50+
import org.springframework.http.HttpMethod;
51+
import org.springframework.http.HttpStatus;
5052
import org.springframework.http.MediaType;
5153
import org.springframework.http.converter.HttpMessageConverter;
5254
import org.springframework.web.servlet.HandlerMapping;
@@ -94,20 +96,30 @@ public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler
9496
}
9597

9698
@Bean
97-
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
98-
GraphQlProperties properties, ResourceLoader resourceLoader) {
99+
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler handler,
100+
GraphQlSource graphQlSource, GraphQlProperties properties, ResourceLoader resourceLoader) {
101+
99102
String graphQLPath = properties.getPath();
100103
if (logger.isInfoEnabled()) {
101104
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
102105
}
106+
103107
// @formatter:off
104108
RouterFunctions.Builder builder = RouterFunctions.route()
105-
.POST(graphQLPath, contentType(MediaType.APPLICATION_JSON).and(accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
109+
.GET(graphQLPath, request ->
110+
ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED)
111+
.headers(headers -> headers.setAllow(Collections.singleton(HttpMethod.POST)))
112+
.build())
113+
.POST(graphQLPath,
114+
contentType(MediaType.APPLICATION_JSON).and(accept(MediaType.APPLICATION_JSON)),
115+
handler::handleRequest);
116+
106117
if (properties.getGraphiql().isEnabled()) {
107118
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
108119
GraphiQlWebMvcHandler graphiQLHandler = new GraphiQlWebMvcHandler(graphQLPath, resource);
109120
builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::showGraphiQlPage);
110121
}
122+
111123
if (properties.getSchema().getPrinter().isEnabled()) {
112124
SchemaPrinter printer = new SchemaPrinter();
113125
builder = builder.GET(graphQLPath + properties.getSchema().getPrinter().getPath(),

graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlWebFluxAutoConfigurationTests.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.context.annotation.Bean;
3232
import org.springframework.context.annotation.Configuration;
3333
import org.springframework.graphql.web.WebInterceptor;
34+
import org.springframework.http.HttpStatus;
3435
import org.springframework.http.MediaType;
3536
import org.springframework.test.web.reactive.server.WebTestClient;
3637

@@ -63,7 +64,6 @@ void query() {
6364
" author" +
6465
" }" +
6566
"}";
66-
6767
client.post().uri("").bodyValue("{ \"query\": \"" + query + "\"}")
6868
.exchange()
6969
.expectStatus()
@@ -74,6 +74,25 @@ void query() {
7474
});
7575
}
7676

77+
@Test
78+
void queryHttpGet() {
79+
testWithWebClient((client) -> {
80+
String query = "{" +
81+
" bookById(id: \\\"book-1\\\"){ " +
82+
" id" +
83+
" name" +
84+
" pageCount" +
85+
" author" +
86+
" }" +
87+
"}";
88+
client.get().uri("?query={query}", "{ \"query\": \"" + query + "\"}")
89+
.exchange()
90+
.expectStatus()
91+
.isEqualTo(HttpStatus.METHOD_NOT_ALLOWED)
92+
.expectHeader().valueEquals("Allow", "POST");
93+
});
94+
}
95+
7796
@Test
7897
void queryMissing() {
7998
testWithWebClient((client) ->

graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlWebMvcAutoConfigurationTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class GraphQlWebMvcAutoConfigurationTests {
5858
"spring.graphql.schema.locations=classpath:books/");
5959

6060
@Test
61-
void endpointHandlesGraphQlQuery() {
61+
void query() {
6262
testWith((mockMvc) -> {
6363
String query = "{" +
6464
" bookById(id: \\\"book-1\\\"){ " +
@@ -76,6 +76,23 @@ void endpointHandlesGraphQlQuery() {
7676
});
7777
}
7878

79+
@Test
80+
void queryHttpGet() {
81+
testWith((mockMvc) -> {
82+
String query = "{" +
83+
" bookById(id: \\\"book-1\\\"){ " +
84+
" id" +
85+
" name" +
86+
" pageCount" +
87+
" author" +
88+
" }" +
89+
"}";
90+
mockMvc.perform(get("/graphql?query={query}", "{\"query\": \"" + query + "\"}"))
91+
.andExpect(status().isMethodNotAllowed())
92+
.andExpect(header().string("Allow", "POST"));
93+
});
94+
}
95+
7996
@Test
8097
void missingQuery() {
8198
testWith((mockMvc) -> mockMvc.perform(post("/graphql").content("{}")).andExpect(status().isBadRequest()));

0 commit comments

Comments
 (0)