11package com .graphqljava .defer ;
22
3+ import com .fasterxml .jackson .core .JsonProcessingException ;
4+ import com .fasterxml .jackson .databind .ObjectMapper ;
5+ import graphql .DeferredExecutionResult ;
36import graphql .ExecutionInput ;
47import graphql .ExecutionResult ;
58import graphql .GraphQL ;
9+ import org .reactivestreams .Publisher ;
10+ import org .reactivestreams .Subscriber ;
11+ import org .reactivestreams .Subscription ;
612import org .slf4j .Logger ;
713import org .slf4j .LoggerFactory ;
814import org .springframework .beans .factory .annotation .Autowired ;
1319import org .springframework .web .bind .annotation .ResponseBody ;
1420import org .springframework .web .bind .annotation .RestController ;
1521
22+ import javax .servlet .http .HttpServletResponse ;
23+ import java .io .IOException ;
24+ import java .io .PrintWriter ;
1625import java .util .LinkedHashMap ;
26+ import java .util .List ;
1727import java .util .Map ;
1828
1929@ RestController
2030public class GraphQLController {
2131
2232
33+ public static final String CRLF = "\r \n " ;
2334 @ Autowired
2435 GraphQL graphql ;
2536
37+ @ Autowired
38+ ObjectMapper objectMapper ;
39+
40+
2641 Logger log = LoggerFactory .getLogger (GraphQLController .class );
2742
43+
2844 @ RequestMapping (value = "/graphql" , method = RequestMethod .POST , produces = MediaType .APPLICATION_JSON_VALUE )
2945 @ ResponseBody
30- public Map < String , Object > graphql (@ RequestBody Map <String , Object > body ) {
46+ public void graphql (@ RequestBody Map <String , Object > body , HttpServletResponse httpServletResponse ) throws IOException {
3147 String query = (String ) body .get ("query" );
48+ if (query == null ) {
49+ query = "" ;
50+ }
3251 Map <String , Object > variables = (Map <String , Object >) body .get ("variables" );
3352 if (variables == null ) {
3453 variables = new LinkedHashMap <>();
@@ -39,12 +58,103 @@ public Map<String, Object> graphql(@RequestBody Map<String, Object> body) {
3958 .build ();
4059
4160 ExecutionResult executionResult = graphql .execute (executionInput );
42- Map <String , Object > result = new LinkedHashMap <>();
43- if (executionResult .getErrors ().size () > 0 ) {
44- result .put ("errors" , executionResult .getErrors ());
45- log .error ("Errors: {}" , executionResult .getErrors ());
61+ Map <Object , Object > extensions = executionResult .getExtensions ();
62+ if (extensions != null && extensions .containsKey (GraphQL .DEFERRED_RESULTS )) {
63+ Publisher <DeferredExecutionResult > deferredResults = (Publisher <DeferredExecutionResult >) extensions .get (GraphQL .DEFERRED_RESULTS );
64+ sendDeferResponse (httpServletResponse , executionResult , deferredResults );
65+ } else {
66+ sendNormalResponse (httpServletResponse , executionResult );
67+ }
68+ }
69+
70+ private void sendNormalResponse (HttpServletResponse httpServletResponse , ExecutionResult executionResult ) throws IOException {
71+ Map <String , Object > result = executionResult .toSpecification ();
72+ httpServletResponse .setStatus (HttpServletResponse .SC_OK );
73+ httpServletResponse .setCharacterEncoding ("UTF-8" );
74+ httpServletResponse .setContentType ("application/json" );
75+ String body = objectMapper .writeValueAsString (result );
76+ PrintWriter writer = httpServletResponse .getWriter ();
77+ writer .write (body );
78+ writer .close ();
79+
80+ }
81+
82+ private void sendDeferResponse (HttpServletResponse httpServletResponse , ExecutionResult executionResult , Publisher <DeferredExecutionResult > deferredResults ) throws IOException {
83+ httpServletResponse .setStatus (HttpServletResponse .SC_OK );
84+ httpServletResponse .setCharacterEncoding ("UTF-8" );
85+ httpServletResponse .setContentType ("multipart/mixed; boundary=\" -\" " );
86+ httpServletResponse .setHeader ("Transfer-Encoding" , "chunked" );
87+ PrintWriter writer = httpServletResponse .getWriter ();
88+
89+ writer .write ("---" + CRLF );
90+ DeferPart deferPart = new DeferPart (executionResult .toSpecification ());
91+ String body = deferPart .write ();
92+ writer .write (body );
93+ httpServletResponse .flushBuffer ();
94+
95+ deferredResults .subscribe (new Subscriber <DeferredExecutionResult >() {
96+
97+ Subscription subscription ;
98+
99+ @ Override
100+ public void onSubscribe (Subscription s ) {
101+ subscription = s ;
102+ subscription .request (10 );
103+ }
104+
105+ @ Override
106+ public void onNext (DeferredExecutionResult executionResult ) {
107+ DeferPart deferPart = new DeferPart (executionResult .toSpecification ());
108+ String body = deferPart .write ();
109+ writer .write (body );
110+ try {
111+ httpServletResponse .flushBuffer ();
112+ } catch (IOException e ) {
113+ e .printStackTrace ();
114+ }
115+ subscription .request (10 );
116+ }
117+
118+ @ Override
119+ public void onError (Throwable t ) {
120+ t .printStackTrace ();
121+ }
122+
123+ @ Override
124+ public void onComplete () {
125+ writer .close ();
126+ }
127+ });
128+
129+
130+ }
131+
132+
133+ private class DeferPart {
134+
135+ private Object body ;
136+
137+ public DeferPart (Object data ) {
138+ this .body = data ;
139+ }
140+
141+ public String write () {
142+ StringBuilder result = new StringBuilder ();
143+ String bodyString = bodyToString ();
144+ result .append ("Content-Type: application/json" ).append (CRLF );
145+ result .append ("Content-Length: " ).append (bodyString .length ()).append (CRLF );
146+ result .append (bodyString ).append (CRLF );
147+ result .append (CRLF ).append ("---" ).append (CRLF );
148+ return result .toString ();
46149 }
47- result .put ("data" , executionResult .getData ());
48- return result ;
150+
151+ private String bodyToString () {
152+ try {
153+ return objectMapper .writeValueAsString (body );
154+ } catch (JsonProcessingException e ) {
155+ throw new RuntimeException (e );
156+ }
157+ }
158+
49159 }
50160}
0 commit comments