1
1
package com .graphqljava .defer ;
2
2
3
+ import com .fasterxml .jackson .core .JsonProcessingException ;
4
+ import com .fasterxml .jackson .databind .ObjectMapper ;
5
+ import graphql .DeferredExecutionResult ;
3
6
import graphql .ExecutionInput ;
4
7
import graphql .ExecutionResult ;
5
8
import graphql .GraphQL ;
9
+ import org .reactivestreams .Publisher ;
10
+ import org .reactivestreams .Subscriber ;
11
+ import org .reactivestreams .Subscription ;
6
12
import org .slf4j .Logger ;
7
13
import org .slf4j .LoggerFactory ;
8
14
import org .springframework .beans .factory .annotation .Autowired ;
13
19
import org .springframework .web .bind .annotation .ResponseBody ;
14
20
import org .springframework .web .bind .annotation .RestController ;
15
21
22
+ import javax .servlet .http .HttpServletResponse ;
23
+ import java .io .IOException ;
24
+ import java .io .PrintWriter ;
16
25
import java .util .LinkedHashMap ;
26
+ import java .util .List ;
17
27
import java .util .Map ;
18
28
19
29
@ RestController
20
30
public class GraphQLController {
21
31
22
32
33
+ public static final String CRLF = "\r \n " ;
23
34
@ Autowired
24
35
GraphQL graphql ;
25
36
37
+ @ Autowired
38
+ ObjectMapper objectMapper ;
39
+
40
+
26
41
Logger log = LoggerFactory .getLogger (GraphQLController .class );
27
42
43
+
28
44
@ RequestMapping (value = "/graphql" , method = RequestMethod .POST , produces = MediaType .APPLICATION_JSON_VALUE )
29
45
@ 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 {
31
47
String query = (String ) body .get ("query" );
48
+ if (query == null ) {
49
+ query = "" ;
50
+ }
32
51
Map <String , Object > variables = (Map <String , Object >) body .get ("variables" );
33
52
if (variables == null ) {
34
53
variables = new LinkedHashMap <>();
@@ -39,12 +58,103 @@ public Map<String, Object> graphql(@RequestBody Map<String, Object> body) {
39
58
.build ();
40
59
41
60
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 ();
46
149
}
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
+
49
159
}
50
160
}
0 commit comments