11package graphql .spring .web .reactive .components ;
22
3-
43import com .fasterxml .jackson .databind .ObjectMapper ;
54import graphql .ExecutionResult ;
65import graphql .Internal ;
76import graphql .spring .web .reactive .ExecutionResultHandler ;
87import graphql .spring .web .reactive .GraphQLInvocation ;
98import graphql .spring .web .reactive .GraphQLInvocationData ;
109import org .springframework .beans .factory .annotation .Autowired ;
10+ import org .springframework .http .HttpHeaders ;
11+ import org .springframework .http .HttpStatus ;
1112import org .springframework .http .MediaType ;
1213import org .springframework .web .bind .annotation .RequestBody ;
14+ import org .springframework .web .bind .annotation .RequestHeader ;
1315import org .springframework .web .bind .annotation .RequestMapping ;
1416import org .springframework .web .bind .annotation .RequestMethod ;
1517import org .springframework .web .bind .annotation .RequestParam ;
1618import org .springframework .web .bind .annotation .RestController ;
19+ import org .springframework .web .server .ResponseStatusException ;
1720import org .springframework .web .server .ServerWebExchange ;
1821import reactor .core .publisher .Mono ;
1922
@@ -36,16 +39,55 @@ public class GraphQLController {
3639
3740 @ RequestMapping (value = "${graphql.url:graphql}" ,
3841 method = RequestMethod .POST ,
39- consumes = MediaType .APPLICATION_JSON_VALUE ,
4042 produces = MediaType .APPLICATION_JSON_VALUE )
41- public Object graphqlPOST (@ RequestBody GraphQLRequestBody body ,
42- ServerWebExchange serverWebExchange ) {
43- String query = body .getQuery ();
44- if (query == null ) {
45- query = "" ;
43+ public Object graphqlPOST (
44+ @ RequestHeader (value = HttpHeaders .CONTENT_TYPE , required = false ) String contentType ,
45+ @ RequestParam (value = "query" , required = false ) String query ,
46+ @ RequestParam (value = "operationName" , required = false ) String operationName ,
47+ @ RequestParam (value = "variables" , required = false ) String variablesJson ,
48+ @ RequestBody (required = false ) String body ,
49+ ServerWebExchange serverWebExchange ) throws IOException {
50+
51+ if (body == null ) {
52+ body = "" ;
4653 }
47- Mono <ExecutionResult > executionResult = graphQLInvocation .invoke (new GraphQLInvocationData (query , body .getOperationName (), body .getVariables ()), serverWebExchange );
48- return executionResultHandler .handleExecutionResult (executionResult , serverWebExchange .getResponse ());
54+
55+ // https://graphql.org/learn/serving-over-http/#post-request
56+ //
57+ // A standard GraphQL POST request should use the application/json content type,
58+ // and include a JSON-encoded body of the following form:
59+ //
60+ // {
61+ // "query": "...",
62+ // "operationName": "...",
63+ // "variables": { "myVariable": "someValue", ... }
64+ // }
65+
66+ if (MediaType .APPLICATION_JSON_VALUE .equals (contentType )) {
67+ GraphQLRequestBody request = objectMapper .readValue (body , GraphQLRequestBody .class );
68+ if (request .getQuery () == null ) {
69+ request .setQuery ("" );
70+ }
71+ return executeRequest (request .getQuery (), request .getOperationName (), request .getVariables (), serverWebExchange );
72+ }
73+
74+ // In addition to the above, we recommend supporting two additional cases:
75+ //
76+ // * If the "query" query string parameter is present (as in the GET example above),
77+ // it should be parsed and handled in the same way as the HTTP GET case.
78+
79+ if (query != null ) {
80+ return executeRequest (query , operationName , convertVariablesJson (variablesJson ), serverWebExchange );
81+ }
82+
83+ // * If the "application/graphql" Content-Type header is present,
84+ // treat the HTTP POST body contents as the GraphQL query string.
85+
86+ if ("application/graphql" .equals (contentType )) {
87+ return executeRequest (body , null , null , serverWebExchange );
88+ }
89+
90+ throw new ResponseStatusException (HttpStatus .UNPROCESSABLE_ENTITY , "Could not process GraphQL request" );
4991 }
5092
5193 @ RequestMapping (value = "${graphql.url:graphql}" ,
@@ -55,10 +97,28 @@ public Object graphqlGET(
5597 @ RequestParam ("query" ) String query ,
5698 @ RequestParam (value = "operationName" , required = false ) String operationName ,
5799 @ RequestParam (value = "variables" , required = false ) String variablesJson ,
58- ServerWebExchange serverWebExchange
59- ) {
60- Mono <ExecutionResult > executionResult = graphQLInvocation .invoke (new GraphQLInvocationData (query , operationName , convertVariablesJson (variablesJson )), serverWebExchange );
61- return executionResultHandler .handleExecutionResult (executionResult , serverWebExchange .getResponse ());
100+ ServerWebExchange serverWebExchange ) {
101+
102+ // https://graphql.org/learn/serving-over-http/#get-request
103+ //
104+ // When receiving an HTTP GET request, the GraphQL query should be specified in the "query" query string.
105+ // For example, if we wanted to execute the following GraphQL query:
106+ //
107+ // {
108+ // me {
109+ // name
110+ // }
111+ // }
112+ //
113+ // This request could be sent via an HTTP GET like so:
114+ //
115+ // http://myapi/graphql?query={me{name}}
116+ //
117+ // Query variables can be sent as a JSON-encoded string in an additional query parameter called "variables".
118+ // If the query contains several named operations,
119+ // an "operationName" query parameter can be used to control which one should be executed.
120+
121+ return executeRequest (query , operationName , convertVariablesJson (variablesJson ), serverWebExchange );
62122 }
63123
64124 private Map <String , Object > convertVariablesJson (String jsonMap ) {
@@ -71,5 +131,14 @@ private Map<String, Object> convertVariablesJson(String jsonMap) {
71131
72132 }
73133
134+ private Object executeRequest (
135+ String query ,
136+ String operationName ,
137+ Map <String , Object > variables ,
138+ ServerWebExchange serverWebExchange ) {
139+ GraphQLInvocationData invocationData = new GraphQLInvocationData (query , operationName , variables );
140+ Mono <ExecutionResult > executionResult = graphQLInvocation .invoke (invocationData , serverWebExchange );
141+ return executionResultHandler .handleExecutionResult (executionResult , serverWebExchange .getResponse ());
142+ }
74143
75144}
0 commit comments