@@ -21,7 +21,6 @@ class HttpLink extends Link {
2121 HttpLink ({
2222 @required String uri,
2323 bool includeExtensions,
24- bool useGETForQueries = false ,
2524
2625 /// pass on customized httpClient, especially handy for mocking and testing
2726 Client httpClient,
@@ -49,7 +48,6 @@ class HttpLink extends Link {
4948 final HttpConfig linkConfig = HttpConfig (
5049 http: HttpQueryOptions (
5150 includeExtensions: includeExtensions,
52- useGETForQueries: useGETForQueries,
5351 ),
5452 options: fetchOptions,
5553 credentials: credentials,
@@ -60,42 +58,44 @@ class HttpLink extends Link {
6058 HttpConfig contextConfig;
6159
6260 if (context != null ) {
63- // TODO: for backwards-compatability fallback to overall context for http options
64- dynamic httpContext = context['http' ] ?? context ?? {};
6561 // TODO: refactor context to use a [HttpConfig] object to avoid dynamic types
6662 contextConfig = HttpConfig (
6763 http: HttpQueryOptions (
68- includeQuery: httpContext['includeQuery' ] as bool ,
69- includeExtensions: httpContext['includeExtensions' ] as bool ,
70- useGETForQueries: httpContext['useGETForQueries' ] as bool ,
64+ includeExtensions: context['includeExtensions' ] as bool ,
7165 ),
7266 options: context['fetchOptions' ] as Map <String , dynamic >,
7367 credentials: context['credentials' ] as Map <String , dynamic >,
7468 headers: context['headers' ] as Map <String , String >,
7569 );
7670 }
7771
78- final HttpConfig config = _mergeHttpConfigs (
72+ final HttpHeadersAndBody httpHeadersAndBody =
73+ _selectHttpOptionsAndBody (
74+ operation,
7975 fallbackHttpConfig,
8076 linkConfig,
8177 contextConfig,
8278 );
8379
80+ final Map <String , String > httpHeaders = httpHeadersAndBody.headers;
81+
8482 StreamController <FetchResult > controller;
8583
8684 Future <void > onListen () async {
8785 StreamedResponse response;
8886
8987 try {
9088 // httpOptionsAndBody.body as String
91- final BaseRequest request = await _prepareRequest (parsedUri, operation, config);
89+ final BaseRequest request = await _prepareRequest (
90+ parsedUri, httpHeadersAndBody.body, httpHeaders);
9291
9392 response = await fetcher.send (request);
9493
9594 operation.setContext (< String , StreamedResponse > {
9695 'response' : response,
9796 });
98- final FetchResult parsedResponse = await _parseResponse (response);
97+ final FetchResult parsedResponse =
98+ await _parseResponse (response);
9999
100100 controller.add (parsedResponse);
101101 } catch (failure) {
@@ -163,31 +163,18 @@ Future<Map<String, MultipartFile>> _getFileMap(
163163
164164Future <BaseRequest > _prepareRequest (
165165 Uri uri,
166- Operation operation ,
167- HttpConfig config ,
166+ Map < String , dynamic > body ,
167+ Map < String , String > httpHeaders ,
168168) async {
169- final httpHeaders = config.headers;
170- final body = _buildBody (operation, config);
171-
172169 final Map <String , MultipartFile > fileMap = await _getFileMap (body);
173170 if (fileMap.isEmpty) {
174- if (operation.isQuery && config.http.useGETForQueries) {
175- config.options['method' ] = 'GET' ;
176- }
177-
178- final httpMethod = config.options['method' ]? .toString ()? .toUpperCase () ?? 'POST' ;
179- if (httpMethod == 'GET' ) {
180- uri = uri.replace (queryParameters: body.map ((k, v) => MapEntry (k, v is String ? v : json.encode (v))));
181- }
182- final Request r = Request (httpMethod, uri);
171+ final Request r = Request ('post' , uri);
183172 r.headers.addAll (httpHeaders);
184- if (httpMethod != 'GET' ) {
185- r.body = json.encode (body);
186- }
173+ r.body = json.encode (body);
187174 return r;
188175 }
189176
190- final MultipartRequest r = MultipartRequest ('POST ' , uri);
177+ final MultipartRequest r = MultipartRequest ('post ' , uri);
191178 r.headers.addAll (httpHeaders);
192179 r.fields['operations' ] = json.encode (body, toEncodable: (dynamic object) {
193180 if (object is MultipartFile ) {
@@ -230,67 +217,97 @@ Future<BaseRequest> _prepareRequest(
230217 return r;
231218}
232219
233- HttpConfig _mergeHttpConfigs (
220+ HttpHeadersAndBody _selectHttpOptionsAndBody (
221+ Operation operation,
234222 HttpConfig fallbackConfig, [
235223 HttpConfig linkConfig,
236224 HttpConfig contextConfig,
237225]) {
226+ final Map <String , dynamic > options = < String , dynamic > {
227+ 'headers' : < String , String > {},
228+ 'credentials' : < String , dynamic > {},
229+ };
230+ final HttpQueryOptions http = HttpQueryOptions ();
231+
238232 // http options
239- final HttpQueryOptions httpQueryOptions = HttpQueryOptions ();
240233
241234 // initialize with fallback http options
242- httpQueryOptions .addAll (fallbackConfig.http);
235+ http .addAll (fallbackConfig.http);
243236
244237 // inject the configured http options
245238 if (linkConfig.http != null ) {
246- httpQueryOptions .addAll (linkConfig.http);
239+ http .addAll (linkConfig.http);
247240 }
248241
249242 // override with context http options
250243 if (contextConfig.http != null ) {
251- httpQueryOptions .addAll (contextConfig.http);
244+ http .addAll (contextConfig.http);
252245 }
253246
254- return HttpConfig (
255- http: httpQueryOptions,
256- options: {
257- ...fallbackConfig.options,
258- ...(linkConfig != null ? linkConfig.options ?? {} : {}),
259- ...(contextConfig != null ? contextConfig.options ?? {} : {}),
260- },
261- credentials: {
262- ...fallbackConfig.credentials,
263- ...(linkConfig != null ? linkConfig.credentials ?? {} : {}),
264- ...(contextConfig != null ? contextConfig.credentials ?? {} : {}),
265- },
266- headers: {
267- ...fallbackConfig.headers,
268- ...(linkConfig != null ? linkConfig.headers ?? {} : {}),
269- ...(contextConfig != null ? contextConfig.headers ?? {} : {}),
270- },
271- );
272- }
247+ // options
248+
249+ // initialize with fallback options
250+ options.addAll (fallbackConfig.options);
251+
252+ // inject the configured options
253+ if (linkConfig.options != null ) {
254+ options.addAll (linkConfig.options);
255+ }
256+
257+ // override with context options
258+ if (contextConfig.options != null ) {
259+ options.addAll (contextConfig.options);
260+ }
261+
262+ // headers
263+
264+ // initialze with fallback headers
265+ options['headers' ].addAll (fallbackConfig.headers);
266+
267+ // inject the configured headers
268+ if (linkConfig.headers != null ) {
269+ options['headers' ].addAll (linkConfig.headers);
270+ }
271+
272+ // inject the context headers
273+ if (contextConfig.headers != null ) {
274+ options['headers' ].addAll (contextConfig.headers);
275+ }
276+
277+ // credentials
278+
279+ // initialze with fallback credentials
280+ options['credentials' ].addAll (fallbackConfig.credentials);
281+
282+ // inject the configured credentials
283+ if (linkConfig.credentials != null ) {
284+ options['credentials' ].addAll (linkConfig.credentials);
285+ }
286+
287+ // inject the context credentials
288+ if (contextConfig.credentials != null ) {
289+ options['credentials' ].addAll (contextConfig.credentials);
290+ }
273291
274- Map <String , dynamic > _buildBody (
275- Operation operation,
276- HttpConfig config,
277- ) {
278292 // the body depends on the http options
279293 final Map <String , dynamic > body = < String , dynamic > {
280294 'operationName' : operation.operationName,
281295 'variables' : operation.variables,
282- };
296+ };
283297
284298 // not sending the query (i.e persisted queries)
285- if (config. http.includeExtensions) {
299+ if (http.includeExtensions) {
286300 body['extensions' ] = operation.extensions;
287301 }
288302
289- if (config. http.includeQuery) {
303+ if (http.includeQuery) {
290304 body['query' ] = printNode (operation.documentNode);
291305 }
292306
293- return body;
307+ return HttpHeadersAndBody (
308+ headers: options['headers' ] as Map <String , String >,
309+ body: body,
310+ );
294311}
295312
296313Future <FetchResult > _parseResponse (StreamedResponse response) async {
@@ -301,11 +318,13 @@ Future<FetchResult> _parseResponse(StreamedResponse response) async {
301318 final Uint8List responseByte = await response.stream.toBytes ();
302319 final String decodedBody = encoding.decode (responseByte);
303320
304- final Map <String , dynamic > jsonResponse =
305- json.decode (decodedBody) as Map <String , dynamic >;
306- final FetchResult fetchResult = FetchResult (
307- statusCode: statusCode,
308- );
321+ Map <String , dynamic > jsonResponse;
322+ try {
323+ jsonResponse= json.decode (decodedBody) as Map <String , dynamic >;
324+ }catch (e){
325+ throw ClientException ('Invalid response body: $decodedBody ' );
326+ }
327+ final FetchResult fetchResult = FetchResult ();
309328
310329 if (jsonResponse['errors' ] != null ) {
311330 fetchResult.errors =
0 commit comments