5
5
import graphql .ExecutionResult ;
6
6
import graphql .introspection .IntrospectionQuery ;
7
7
import graphql .schema .GraphQLFieldDefinition ;
8
- import graphql .servlet .internal .GraphQLRequest ;
9
- import graphql .servlet .internal .VariableMapper ;
8
+ import graphql .servlet .core .GraphQLMBean ;
9
+ import graphql .servlet .core .GraphQLObjectMapper ;
10
+ import graphql .servlet .core .GraphQLQueryInvoker ;
11
+ import graphql .servlet .core .GraphQLServletListener ;
12
+ import graphql .servlet .config .GraphQLConfiguration ;
13
+ import graphql .servlet .context .ContextSetting ;
14
+ import graphql .servlet .input .BatchInputPreProcessResult ;
15
+ import graphql .servlet .input .BatchInputPreProcessor ;
16
+ import graphql .servlet .input .GraphQLBatchedInvocationInput ;
17
+ import graphql .servlet .input .GraphQLSingleInvocationInput ;
18
+ import graphql .servlet .input .GraphQLInvocationInputFactory ;
19
+ import graphql .servlet .core .internal .GraphQLRequest ;
20
+ import graphql .servlet .core .internal .VariableMapper ;
10
21
import org .reactivestreams .Publisher ;
11
22
import org .reactivestreams .Subscriber ;
12
23
import org .reactivestreams .Subscription ;
30
41
import java .util .ArrayList ;
31
42
import java .util .Arrays ;
32
43
import java .util .HashMap ;
44
+ import java .util .Iterator ;
33
45
import java .util .List ;
34
46
import java .util .Map ;
35
47
import java .util .Objects ;
46
58
*/
47
59
public abstract class AbstractGraphQLHttpServlet extends HttpServlet implements Servlet , GraphQLMBean {
48
60
49
- public static final Logger log = LoggerFactory .getLogger (AbstractGraphQLHttpServlet .class );
61
+ private static final Logger log = LoggerFactory .getLogger (AbstractGraphQLHttpServlet .class );
50
62
51
- public static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8" ;
52
- public static final String APPLICATION_EVENT_STREAM_UTF8 = "text/event-stream;charset=UTF-8" ;
53
- public static final String APPLICATION_GRAPHQL = "application/graphql" ;
54
- public static final int STATUS_OK = 200 ;
55
- public static final int STATUS_BAD_REQUEST = 400 ;
63
+ private static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8" ;
64
+ private static final String APPLICATION_EVENT_STREAM_UTF8 = "text/event-stream;charset=UTF-8" ;
65
+ private static final String APPLICATION_GRAPHQL = "application/graphql" ;
66
+ private static final int STATUS_OK = 200 ;
67
+ private static final int STATUS_BAD_REQUEST = 400 ;
56
68
57
69
private static final GraphQLRequest INTROSPECTION_REQUEST = new GraphQLRequest (IntrospectionQuery .INTROSPECTION_QUERY , new HashMap <>(), null );
58
70
private static final String [] MULTIPART_KEYS = new String []{"operations" , "graphql" , "query" };
@@ -123,13 +135,17 @@ public void init() {
123
135
path = request .getServletPath ();
124
136
}
125
137
if (path .contentEquals ("/schema.json" )) {
126
- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (INTROSPECTION_REQUEST , request , response ), response );
138
+ query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (INTROSPECTION_REQUEST , request , response ),
139
+ request , response );
127
140
} else {
128
141
String query = request .getParameter ("query" );
129
142
if (query != null ) {
130
143
131
144
if (isBatchedQuery (query )) {
132
- queryBatched (queryInvoker , graphQLObjectMapper , invocationInputFactory .createReadOnly (graphQLObjectMapper .readBatchedGraphQLRequest (query ), request , response ), response );
145
+ List <GraphQLRequest > requests = graphQLObjectMapper .readBatchedGraphQLRequest (query );
146
+ GraphQLBatchedInvocationInput batchedInvocationInput =
147
+ invocationInputFactory .createReadOnly (configuration .getContextSetting (), requests , request , response );
148
+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
133
149
} else {
134
150
final Map <String , Object > variables = new HashMap <>();
135
151
if (request .getParameter ("variables" ) != null ) {
@@ -138,7 +154,9 @@ public void init() {
138
154
139
155
String operationName = request .getParameter ("operationName" );
140
156
141
- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .createReadOnly (new GraphQLRequest (query , variables , operationName ), request , response ), response );
157
+ query (queryInvoker , graphQLObjectMapper ,
158
+ invocationInputFactory .createReadOnly (new GraphQLRequest (query , variables , operationName ), request , response ),
159
+ request , response );
142
160
}
143
161
} else {
144
162
response .setStatus (STATUS_BAD_REQUEST );
@@ -155,7 +173,9 @@ public void init() {
155
173
try {
156
174
if (APPLICATION_GRAPHQL .equals (request .getContentType ())) {
157
175
String query = CharStreams .toString (request .getReader ());
158
- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (new GraphQLRequest (query , null , null ), request , response ), response );
176
+ query (queryInvoker , graphQLObjectMapper ,
177
+ invocationInputFactory .create (new GraphQLRequest (query , null , null ), request , response ),
178
+ request , response );
159
179
} else if (request .getContentType () != null && request .getContentType ().startsWith ("multipart/form-data" ) && !request .getParts ().isEmpty ()) {
160
180
final Map <String , List <Part >> fileItems = request .getParts ()
161
181
.stream ()
@@ -182,10 +202,9 @@ public void init() {
182
202
List <GraphQLRequest > graphQLRequests =
183
203
graphQLObjectMapper .readBatchedGraphQLRequest (inputStream );
184
204
variablesMap .ifPresent (map -> graphQLRequests .forEach (r -> mapMultipartVariables (r , map , fileItems )));
185
- GraphQLBatchedInvocationInput invocationInput =
186
- invocationInputFactory .create (graphQLRequests , request , response );
187
- invocationInput .getContext ().setParts (fileItems );
188
- queryBatched (queryInvoker , graphQLObjectMapper , invocationInput , response );
205
+ GraphQLBatchedInvocationInput batchedInvocationInput = invocationInputFactory .create (configuration .getContextSetting (),
206
+ graphQLRequests , request , response );
207
+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
189
208
return ;
190
209
} else {
191
210
GraphQLRequest graphQLRequest ;
@@ -198,8 +217,7 @@ public void init() {
198
217
variablesMap .ifPresent (m -> mapMultipartVariables (graphQLRequest , m , fileItems ));
199
218
GraphQLSingleInvocationInput invocationInput =
200
219
invocationInputFactory .create (graphQLRequest , request , response );
201
- invocationInput .getContext ().setParts (fileItems );
202
- query (queryInvoker , graphQLObjectMapper , invocationInput , response );
220
+ query (queryInvoker , graphQLObjectMapper , invocationInput , request , response );
203
221
return ;
204
222
}
205
223
}
@@ -211,9 +229,12 @@ public void init() {
211
229
InputStream inputStream = asMarkableInputStream (request .getInputStream ());
212
230
213
231
if (isBatchedQuery (inputStream )) {
214
- queryBatched (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readBatchedGraphQLRequest (inputStream ), request , response ), response );
232
+ List <GraphQLRequest > requests = graphQLObjectMapper .readBatchedGraphQLRequest (inputStream );
233
+ GraphQLBatchedInvocationInput batchedInvocationInput =
234
+ invocationInputFactory .create (configuration .getContextSetting (), requests , request , response );
235
+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
215
236
} else {
216
- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readGraphQLRequest (inputStream ), request , response ), response );
237
+ query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readGraphQLRequest (inputStream ), request , response ), request , response );
217
238
}
218
239
}
219
240
} catch (Exception e ) {
@@ -348,18 +369,21 @@ private Optional<Part> getFileItem(Map<String, List<Part>> fileItems, String nam
348
369
return Optional .ofNullable (fileItems .get (name )).filter (list -> !list .isEmpty ()).map (list -> list .get (0 ));
349
370
}
350
371
351
- private void query (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLSingleInvocationInput invocationInput , HttpServletResponse resp ) throws IOException {
372
+ private void query (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLSingleInvocationInput invocationInput ,
373
+ HttpServletRequest req , HttpServletResponse resp ) throws IOException {
352
374
ExecutionResult result = queryInvoker .query (invocationInput );
353
375
354
376
if (!(result .getData () instanceof Publisher )) {
355
377
resp .setContentType (APPLICATION_JSON_UTF8 );
356
378
resp .setStatus (STATUS_OK );
357
379
resp .getWriter ().write (graphQLObjectMapper .serializeResultAsJson (result ));
358
380
} else {
381
+ if (req == null ) {
382
+ throw new IllegalStateException ("Http servlet request can not be null" );
383
+ }
359
384
resp .setContentType (APPLICATION_EVENT_STREAM_UTF8 );
360
385
resp .setStatus (STATUS_OK );
361
386
362
- HttpServletRequest req = invocationInput .getContext ().getHttpServletRequest ().orElseThrow (IllegalStateException ::new );
363
387
boolean isInAsyncThread = req .isAsyncStarted ();
364
388
AsyncContext asyncContext = isInAsyncThread ? req .getAsyncContext () : req .startAsync (req , resp );
365
389
asyncContext .setTimeout (configuration .getSubscriptionTimeout ());
@@ -378,8 +402,30 @@ private void query(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQL
378
402
}
379
403
}
380
404
381
- private void queryBatched (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLBatchedInvocationInput invocationInput , HttpServletResponse resp ) throws Exception {
382
- queryInvoker .query (invocationInput , resp , graphQLObjectMapper );
405
+ private void queryBatched (GraphQLQueryInvoker queryInvoker , GraphQLBatchedInvocationInput batchedInvocationInput , HttpServletRequest request ,
406
+ HttpServletResponse response , GraphQLConfiguration configuration ) throws IOException {
407
+ BatchInputPreProcessor batchInputPreProcessor = configuration .getBatchInputPreProcessor ();
408
+ ContextSetting contextSetting = configuration .getContextSetting ();
409
+ BatchInputPreProcessResult batchInputPreProcessResult = batchInputPreProcessor .preProcessBatch (batchedInvocationInput , request , response );
410
+ if (batchInputPreProcessResult .isExecutable ()) {
411
+ List <ExecutionResult > results = queryInvoker .query (batchInputPreProcessResult .getBatchedInvocationInput ().getExecutionInputs (),
412
+ contextSetting );
413
+ response .setContentType (AbstractGraphQLHttpServlet .APPLICATION_JSON_UTF8 );
414
+ response .setStatus (AbstractGraphQLHttpServlet .STATUS_OK );
415
+ Writer writer = response .getWriter ();
416
+ Iterator <ExecutionResult > executionInputIterator = results .iterator ();
417
+ writer .write ("[" );
418
+ GraphQLObjectMapper graphQLObjectMapper = configuration .getObjectMapper ();
419
+ while (executionInputIterator .hasNext ()) {
420
+ writer .write (graphQLObjectMapper .serializeResultAsJson (executionInputIterator .next ()));
421
+ if (executionInputIterator .hasNext ()) {
422
+ writer .write ("," );
423
+ }
424
+ }
425
+ writer .write ("]" );
426
+ } else {
427
+ response .sendError (batchInputPreProcessResult .getStatusCode (), batchInputPreProcessResult .getStatusMessage ());
428
+ }
383
429
}
384
430
385
431
private <R > List <R > runListeners (Function <? super GraphQLServletListener , R > action ) {
0 commit comments