Committed by
GitHub
Merge pull request #2448 from wheeOs/wheeOs-response-interception
response interception
Showing
3 changed files
with
58 additions
and
3 deletions
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | import 'dart:convert'; | 2 | import 'dart:convert'; |
3 | +import 'dart:io'; | ||
3 | 4 | ||
4 | import '../src/certificates/certificates.dart'; | 5 | import '../src/certificates/certificates.dart'; |
5 | import '../src/exceptions/exceptions.dart'; | 6 | import '../src/exceptions/exceptions.dart'; |
@@ -15,6 +16,8 @@ typedef Decoder<T> = T Function(dynamic data); | @@ -15,6 +16,8 @@ typedef Decoder<T> = T Function(dynamic data); | ||
15 | 16 | ||
16 | typedef Progress = Function(double percent); | 17 | typedef Progress = Function(double percent); |
17 | 18 | ||
19 | +typedef ResponseInterceptor<T> = Future<Response<T>?> Function(Request<T> request, Type targetType, HttpClientResponse response); | ||
20 | + | ||
18 | class GetHttpClient { | 21 | class GetHttpClient { |
19 | String userAgent; | 22 | String userAgent; |
20 | String? baseUrl; | 23 | String? baseUrl; |
@@ -29,6 +32,7 @@ class GetHttpClient { | @@ -29,6 +32,7 @@ class GetHttpClient { | ||
29 | bool sendContentLength; | 32 | bool sendContentLength; |
30 | 33 | ||
31 | Decoder? defaultDecoder; | 34 | Decoder? defaultDecoder; |
35 | + ResponseInterceptor? defaultResponseInterceptor; | ||
32 | 36 | ||
33 | Duration timeout; | 37 | Duration timeout; |
34 | 38 | ||
@@ -99,6 +103,7 @@ class GetHttpClient { | @@ -99,6 +103,7 @@ class GetHttpClient { | ||
99 | String method, | 103 | String method, |
100 | Map<String, dynamic>? query, | 104 | Map<String, dynamic>? query, |
101 | Decoder<T>? decoder, | 105 | Decoder<T>? decoder, |
106 | + ResponseInterceptor<T>? responseInterceptor, | ||
102 | Progress? uploadProgress, | 107 | Progress? uploadProgress, |
103 | ) async { | 108 | ) async { |
104 | List<int>? bodyBytes; | 109 | List<int>? bodyBytes; |
@@ -111,7 +116,7 @@ class GetHttpClient { | @@ -111,7 +116,7 @@ class GetHttpClient { | ||
111 | 116 | ||
112 | if (body is FormData) { | 117 | if (body is FormData) { |
113 | bodyBytes = await body.toBytes(); | 118 | bodyBytes = await body.toBytes(); |
114 | - _setContentLenght(headers, bodyBytes.length); | 119 | + headers['content-length'] = bodyBytes.length.toString(); |
115 | headers['content-type'] = | 120 | headers['content-type'] = |
116 | 'multipart/form-data; boundary=${body.boundary}'; | 121 | 'multipart/form-data; boundary=${body.boundary}'; |
117 | } else if (contentType != null && | 122 | } else if (contentType != null && |
@@ -159,6 +164,7 @@ class GetHttpClient { | @@ -159,6 +164,7 @@ class GetHttpClient { | ||
159 | followRedirects: followRedirects, | 164 | followRedirects: followRedirects, |
160 | maxRedirects: maxRedirects, | 165 | maxRedirects: maxRedirects, |
161 | decoder: decoder, | 166 | decoder: decoder, |
167 | + responseInterceptor: responseInterceptor | ||
162 | ); | 168 | ); |
163 | } | 169 | } |
164 | 170 | ||
@@ -267,6 +273,7 @@ class GetHttpClient { | @@ -267,6 +273,7 @@ class GetHttpClient { | ||
267 | String? contentType, | 273 | String? contentType, |
268 | Map<String, dynamic>? query, | 274 | Map<String, dynamic>? query, |
269 | Decoder<T>? decoder, | 275 | Decoder<T>? decoder, |
276 | + ResponseInterceptor<T>? responseInterceptor, | ||
270 | ) { | 277 | ) { |
271 | final headers = <String, String>{}; | 278 | final headers = <String, String>{}; |
272 | _setSimpleHeaders(headers, contentType); | 279 | _setSimpleHeaders(headers, contentType); |
@@ -277,12 +284,21 @@ class GetHttpClient { | @@ -277,12 +284,21 @@ class GetHttpClient { | ||
277 | url: uri, | 284 | url: uri, |
278 | headers: headers, | 285 | headers: headers, |
279 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), | 286 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), |
287 | + responseInterceptor: _responseInterceptor(responseInterceptor), | ||
280 | contentLength: 0, | 288 | contentLength: 0, |
281 | followRedirects: followRedirects, | 289 | followRedirects: followRedirects, |
282 | maxRedirects: maxRedirects, | 290 | maxRedirects: maxRedirects, |
283 | )); | 291 | )); |
284 | } | 292 | } |
285 | 293 | ||
294 | + ResponseInterceptor<T>? _responseInterceptor<T>(ResponseInterceptor<T>? actual) { | ||
295 | + if(actual != null) return actual; | ||
296 | + final defaultInterceptor = defaultResponseInterceptor; | ||
297 | + return defaultInterceptor != null | ||
298 | + ? (request, targetType, response) async => await defaultInterceptor(request, targetType, response) as Response<T>? | ||
299 | + : null; | ||
300 | + } | ||
301 | + | ||
286 | Future<Request<T>> _request<T>( | 302 | Future<Request<T>> _request<T>( |
287 | String? url, | 303 | String? url, |
288 | String method, { | 304 | String method, { |
@@ -290,6 +306,7 @@ class GetHttpClient { | @@ -290,6 +306,7 @@ class GetHttpClient { | ||
290 | required dynamic body, | 306 | required dynamic body, |
291 | required Map<String, dynamic>? query, | 307 | required Map<String, dynamic>? query, |
292 | Decoder<T>? decoder, | 308 | Decoder<T>? decoder, |
309 | + ResponseInterceptor<T>? responseInterceptor, | ||
293 | required Progress? uploadProgress, | 310 | required Progress? uploadProgress, |
294 | }) { | 311 | }) { |
295 | return _requestWithBody<T>( | 312 | return _requestWithBody<T>( |
@@ -299,6 +316,7 @@ class GetHttpClient { | @@ -299,6 +316,7 @@ class GetHttpClient { | ||
299 | method, | 316 | method, |
300 | query, | 317 | query, |
301 | decoder ?? (defaultDecoder as Decoder<T>?), | 318 | decoder ?? (defaultDecoder as Decoder<T>?), |
319 | + _responseInterceptor(responseInterceptor), | ||
302 | uploadProgress, | 320 | uploadProgress, |
303 | ); | 321 | ); |
304 | } | 322 | } |
@@ -308,6 +326,7 @@ class GetHttpClient { | @@ -308,6 +326,7 @@ class GetHttpClient { | ||
308 | String? contentType, | 326 | String? contentType, |
309 | Map<String, dynamic>? query, | 327 | Map<String, dynamic>? query, |
310 | Decoder<T>? decoder, | 328 | Decoder<T>? decoder, |
329 | + ResponseInterceptor<T>? responseInterceptor, | ||
311 | ) { | 330 | ) { |
312 | final headers = <String, String>{}; | 331 | final headers = <String, String>{}; |
313 | _setSimpleHeaders(headers, contentType); | 332 | _setSimpleHeaders(headers, contentType); |
@@ -318,8 +337,22 @@ class GetHttpClient { | @@ -318,8 +337,22 @@ class GetHttpClient { | ||
318 | url: uri, | 337 | url: uri, |
319 | headers: headers, | 338 | headers: headers, |
320 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), | 339 | decoder: decoder ?? (defaultDecoder as Decoder<T>?), |
340 | + responseInterceptor: _responseInterceptor(responseInterceptor), | ||
321 | ); | 341 | ); |
322 | } | 342 | } |
343 | + Future<Response<T>> send<T>(Request<T> request) async { | ||
344 | + try { | ||
345 | + var response = await _performRequest<T>(() => Future.value(request)); | ||
346 | + return response; | ||
347 | + } on Exception catch (e) { | ||
348 | + if (!errorSafety) { | ||
349 | + throw GetHttpException(e.toString()); | ||
350 | + } | ||
351 | + return Future.value(Response<T>( | ||
352 | + statusText: 'Can not connect to server. Reason: $e', | ||
353 | + )); | ||
354 | + } | ||
355 | + } | ||
323 | 356 | ||
324 | Future<Response<T>> patch<T>( | 357 | Future<Response<T>> patch<T>( |
325 | String url, { | 358 | String url, { |
@@ -328,6 +361,7 @@ class GetHttpClient { | @@ -328,6 +361,7 @@ class GetHttpClient { | ||
328 | Map<String, String>? headers, | 361 | Map<String, String>? headers, |
329 | Map<String, dynamic>? query, | 362 | Map<String, dynamic>? query, |
330 | Decoder<T>? decoder, | 363 | Decoder<T>? decoder, |
364 | + ResponseInterceptor<T>? responseInterceptor, | ||
331 | Progress? uploadProgress, | 365 | Progress? uploadProgress, |
332 | // List<MultipartFile> files, | 366 | // List<MultipartFile> files, |
333 | }) async { | 367 | }) async { |
@@ -340,6 +374,7 @@ class GetHttpClient { | @@ -340,6 +374,7 @@ class GetHttpClient { | ||
340 | body: body, | 374 | body: body, |
341 | query: query, | 375 | query: query, |
342 | decoder: decoder, | 376 | decoder: decoder, |
377 | + responseInterceptor: responseInterceptor, | ||
343 | uploadProgress: uploadProgress, | 378 | uploadProgress: uploadProgress, |
344 | ), | 379 | ), |
345 | headers: headers, | 380 | headers: headers, |
@@ -362,6 +397,7 @@ class GetHttpClient { | @@ -362,6 +397,7 @@ class GetHttpClient { | ||
362 | Map<String, String>? headers, | 397 | Map<String, String>? headers, |
363 | Map<String, dynamic>? query, | 398 | Map<String, dynamic>? query, |
364 | Decoder<T>? decoder, | 399 | Decoder<T>? decoder, |
400 | + ResponseInterceptor<T>? responseInterceptor, | ||
365 | Progress? uploadProgress, | 401 | Progress? uploadProgress, |
366 | // List<MultipartFile> files, | 402 | // List<MultipartFile> files, |
367 | }) async { | 403 | }) async { |
@@ -374,6 +410,7 @@ class GetHttpClient { | @@ -374,6 +410,7 @@ class GetHttpClient { | ||
374 | body: body, | 410 | body: body, |
375 | query: query, | 411 | query: query, |
376 | decoder: decoder, | 412 | decoder: decoder, |
413 | + responseInterceptor: responseInterceptor, | ||
377 | uploadProgress: uploadProgress, | 414 | uploadProgress: uploadProgress, |
378 | ), | 415 | ), |
379 | headers: headers, | 416 | headers: headers, |
@@ -397,6 +434,7 @@ class GetHttpClient { | @@ -397,6 +434,7 @@ class GetHttpClient { | ||
397 | Map<String, String>? headers, | 434 | Map<String, String>? headers, |
398 | Map<String, dynamic>? query, | 435 | Map<String, dynamic>? query, |
399 | Decoder<T>? decoder, | 436 | Decoder<T>? decoder, |
437 | + ResponseInterceptor<T>? responseInterceptor, | ||
400 | Progress? uploadProgress, | 438 | Progress? uploadProgress, |
401 | }) async { | 439 | }) async { |
402 | try { | 440 | try { |
@@ -408,6 +446,7 @@ class GetHttpClient { | @@ -408,6 +446,7 @@ class GetHttpClient { | ||
408 | query: query, | 446 | query: query, |
409 | body: body, | 447 | body: body, |
410 | decoder: decoder, | 448 | decoder: decoder, |
449 | + responseInterceptor: responseInterceptor, | ||
411 | uploadProgress: uploadProgress, | 450 | uploadProgress: uploadProgress, |
412 | ), | 451 | ), |
413 | headers: headers, | 452 | headers: headers, |
@@ -430,6 +469,7 @@ class GetHttpClient { | @@ -430,6 +469,7 @@ class GetHttpClient { | ||
430 | Map<String, String>? headers, | 469 | Map<String, String>? headers, |
431 | Map<String, dynamic>? query, | 470 | Map<String, dynamic>? query, |
432 | Decoder<T>? decoder, | 471 | Decoder<T>? decoder, |
472 | + ResponseInterceptor<T>? responseInterceptor, | ||
433 | Progress? uploadProgress, | 473 | Progress? uploadProgress, |
434 | }) async { | 474 | }) async { |
435 | try { | 475 | try { |
@@ -441,6 +481,7 @@ class GetHttpClient { | @@ -441,6 +481,7 @@ class GetHttpClient { | ||
441 | query: query, | 481 | query: query, |
442 | body: body, | 482 | body: body, |
443 | decoder: decoder, | 483 | decoder: decoder, |
484 | + responseInterceptor: responseInterceptor, | ||
444 | uploadProgress: uploadProgress, | 485 | uploadProgress: uploadProgress, |
445 | ), | 486 | ), |
446 | headers: headers, | 487 | headers: headers, |
@@ -462,10 +503,11 @@ class GetHttpClient { | @@ -462,10 +503,11 @@ class GetHttpClient { | ||
462 | String? contentType, | 503 | String? contentType, |
463 | Map<String, dynamic>? query, | 504 | Map<String, dynamic>? query, |
464 | Decoder<T>? decoder, | 505 | Decoder<T>? decoder, |
506 | + ResponseInterceptor<T>? responseInterceptor, | ||
465 | }) async { | 507 | }) async { |
466 | try { | 508 | try { |
467 | var response = await _performRequest<T>( | 509 | var response = await _performRequest<T>( |
468 | - () => _get<T>(url, contentType, query, decoder), | 510 | + () => _get<T>(url, contentType, query, decoder, responseInterceptor), |
469 | headers: headers, | 511 | headers: headers, |
470 | ); | 512 | ); |
471 | return response; | 513 | return response; |
@@ -546,10 +588,11 @@ class GetHttpClient { | @@ -546,10 +588,11 @@ class GetHttpClient { | ||
546 | String? contentType, | 588 | String? contentType, |
547 | Map<String, dynamic>? query, | 589 | Map<String, dynamic>? query, |
548 | Decoder<T>? decoder, | 590 | Decoder<T>? decoder, |
591 | + ResponseInterceptor<T>? responseInterceptor | ||
549 | }) async { | 592 | }) async { |
550 | try { | 593 | try { |
551 | var response = await _performRequest<T>( | 594 | var response = await _performRequest<T>( |
552 | - () async => _delete<T>(url, contentType, query, decoder), | 595 | + () async => _delete<T>(url, contentType, query, decoder, responseInterceptor), |
553 | headers: headers, | 596 | headers: headers, |
554 | ); | 597 | ); |
555 | return response; | 598 | return response; |
@@ -8,6 +8,7 @@ import '../../response/response.dart'; | @@ -8,6 +8,7 @@ import '../../response/response.dart'; | ||
8 | import '../interface/request_base.dart'; | 8 | import '../interface/request_base.dart'; |
9 | import '../utils/body_decoder.dart'; | 9 | import '../utils/body_decoder.dart'; |
10 | 10 | ||
11 | + | ||
11 | /// A `dart:io` implementation of `HttpRequestBase`. | 12 | /// A `dart:io` implementation of `HttpRequestBase`. |
12 | class HttpRequestImpl extends HttpRequestBase { | 13 | class HttpRequestImpl extends HttpRequestBase { |
13 | io.HttpClient? _httpClient; | 14 | io.HttpClient? _httpClient; |
@@ -57,6 +58,10 @@ class HttpRequestImpl extends HttpRequestBase { | @@ -57,6 +58,10 @@ class HttpRequestImpl extends HttpRequestBase { | ||
57 | }); | 58 | }); |
58 | 59 | ||
59 | final bodyBytes = (response); | 60 | final bodyBytes = (response); |
61 | + | ||
62 | + final interceptionResponse = await request.responseInterceptor?.call(request, T, response); | ||
63 | + if(interceptionResponse != null) return interceptionResponse; | ||
64 | + | ||
60 | final stringBody = await bodyBytesToString(bodyBytes, headers); | 65 | final stringBody = await bodyBytesToString(bodyBytes, headers); |
61 | 66 | ||
62 | final body = bodyDecoded<T>( | 67 | final body = bodyDecoded<T>( |
@@ -13,6 +13,8 @@ class Request<T> { | @@ -13,6 +13,8 @@ class Request<T> { | ||
13 | final Uri url; | 13 | final Uri url; |
14 | 14 | ||
15 | final Decoder<T>? decoder; | 15 | final Decoder<T>? decoder; |
16 | + | ||
17 | + final ResponseInterceptor<T>? responseInterceptor; | ||
16 | 18 | ||
17 | /// The Http Method from this [Request] | 19 | /// The Http Method from this [Request] |
18 | /// ex: `GET`,`POST`,`PUT`,`DELETE` | 20 | /// ex: `GET`,`POST`,`PUT`,`DELETE` |
@@ -44,6 +46,7 @@ class Request<T> { | @@ -44,6 +46,7 @@ class Request<T> { | ||
44 | required this.files, | 46 | required this.files, |
45 | required this.persistentConnection, | 47 | required this.persistentConnection, |
46 | required this.decoder, | 48 | required this.decoder, |
49 | + this.responseInterceptor, | ||
47 | }); | 50 | }); |
48 | 51 | ||
49 | factory Request({ | 52 | factory Request({ |
@@ -57,6 +60,7 @@ class Request<T> { | @@ -57,6 +60,7 @@ class Request<T> { | ||
57 | FormData? files, | 60 | FormData? files, |
58 | bool persistentConnection = true, | 61 | bool persistentConnection = true, |
59 | Decoder<T>? decoder, | 62 | Decoder<T>? decoder, |
63 | + ResponseInterceptor<T>? responseInterceptor, | ||
60 | }) { | 64 | }) { |
61 | if (followRedirects) { | 65 | if (followRedirects) { |
62 | assert(maxRedirects > 0); | 66 | assert(maxRedirects > 0); |
@@ -72,6 +76,7 @@ class Request<T> { | @@ -72,6 +76,7 @@ class Request<T> { | ||
72 | files: files, | 76 | files: files, |
73 | persistentConnection: persistentConnection, | 77 | persistentConnection: persistentConnection, |
74 | decoder: decoder, | 78 | decoder: decoder, |
79 | + responseInterceptor: responseInterceptor | ||
75 | ); | 80 | ); |
76 | } | 81 | } |
77 | 82 | ||
@@ -87,6 +92,7 @@ class Request<T> { | @@ -87,6 +92,7 @@ class Request<T> { | ||
87 | bool? persistentConnection, | 92 | bool? persistentConnection, |
88 | Decoder<T>? decoder, | 93 | Decoder<T>? decoder, |
89 | bool appendHeader = true, | 94 | bool appendHeader = true, |
95 | + ResponseInterceptor<T>? responseInterceptor, | ||
90 | }) { | 96 | }) { |
91 | // If appendHeader is set to true, we will merge origin headers with that | 97 | // If appendHeader is set to true, we will merge origin headers with that |
92 | if (appendHeader && headers != null) { | 98 | if (appendHeader && headers != null) { |
@@ -104,6 +110,7 @@ class Request<T> { | @@ -104,6 +110,7 @@ class Request<T> { | ||
104 | files: files ?? this.files, | 110 | files: files ?? this.files, |
105 | persistentConnection: persistentConnection ?? this.persistentConnection, | 111 | persistentConnection: persistentConnection ?? this.persistentConnection, |
106 | decoder: decoder ?? this.decoder, | 112 | decoder: decoder ?? this.decoder, |
113 | + responseInterceptor: responseInterceptor ?? this.responseInterceptor | ||
107 | ); | 114 | ); |
108 | } | 115 | } |
109 | } | 116 | } |
-
Please register or login to post a comment