Skip to content

Commit ff8bee2

Browse files
authored
fix: update docs and improve multipart support (#150)
1 parent 5fadc05 commit ff8bee2

8 files changed

+80
-53
lines changed

Diff for: README.md

+13-8
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,26 @@ import 'package:http_interceptor/http_interceptor.dart';
6969

7070
In order to implement `http_interceptor` you need to implement the `InterceptorContract` and create your own interceptor. This abstract class has two methods: `interceptRequest`, which triggers before the http request is called; and `interceptResponse`, which triggers after the request is called, it has a response attached to it which the corresponding to said request. You could use this to do logging, adding headers, error handling, or many other cool stuff. It is important to note that after you proccess the request/response objects you need to return them so that `http` can continue the execute.
7171

72+
`interceptRequest` and `interceptResponse` use `FutureOr` syntax, which makes it easier to support both synchronous and asynchronous behaviors.
73+
7274
- Logging with interceptor:
7375

7476
```dart
7577
class LoggerInterceptor extends InterceptorContract {
7678
@override
77-
Future<BaseRequest> interceptRequest({
79+
BaseRequest interceptRequest({
7880
required BaseRequest request,
79-
}) async {
81+
}) {
8082
print('----- Request -----');
8183
print(request.toString());
8284
print(request.headers.toString());
8385
return request;
8486
}
8587
8688
@override
87-
Future<BaseResponse> interceptResponse({
89+
BaseResponse interceptResponse({
8890
required BaseResponse response,
89-
}) async {
91+
}) {
9092
log('----- Response -----');
9193
log('Code: ${response.statusCode}');
9294
if (response is Response) {
@@ -102,7 +104,7 @@ class LoggerInterceptor extends InterceptorContract {
102104
```dart
103105
class WeatherApiInterceptor implements InterceptorContract {
104106
@override
105-
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
107+
FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
106108
try {
107109
request.url.queryParameters['appid'] = OPEN_WEATHER_API_KEY;
108110
request.url.queryParameters['units'] = 'metric';
@@ -114,7 +116,10 @@ class WeatherApiInterceptor implements InterceptorContract {
114116
}
115117
116118
@override
117-
Future<BaseResponse> interceptResponse({required BaseResponse response}) async => response;
119+
BaseResponse interceptResponse({
120+
required BaseResponse response,
121+
}) =>
122+
response;
118123
}
119124
```
120125

@@ -123,15 +128,15 @@ class WeatherApiInterceptor implements InterceptorContract {
123128
```dart
124129
class MultipartRequestInterceptor implements InterceptorContract {
125130
@override
126-
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
131+
FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
127132
if(request is MultipartRequest){
128133
request.fields['app_version'] = await PackageInfo.fromPlatform().version;
129134
}
130135
return request;
131136
}
132137
133138
@override
134-
Future<BaseResponse> interceptResponse({required BaseResponse response}) async {
139+
FutureOr<BaseResponse> interceptResponse({required BaseResponse response}) async {
135140
if(response is StreamedResponse){
136141
response.stream.asBroadcastStream().listen((data){
137142
print(data);

Diff for: example/lib/common.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import 'package:http_interceptor/http_interceptor.dart';
44

55
class LoggerInterceptor extends InterceptorContract {
66
@override
7-
Future<BaseRequest> interceptRequest({
7+
BaseRequest interceptRequest({
88
required BaseRequest request,
9-
}) async {
9+
}) {
1010
log('----- Request -----');
1111
log(request.toString());
1212
log(request.headers.toString());
@@ -15,9 +15,9 @@ class LoggerInterceptor extends InterceptorContract {
1515
}
1616

1717
@override
18-
Future<BaseResponse> interceptResponse({
18+
BaseResponse interceptResponse({
1919
required BaseResponse response,
20-
}) async {
20+
}) {
2121
log('----- Response -----');
2222
log('Code: ${response.statusCode}');
2323
log('Response type: ${response.runtimeType}');

Diff for: example/lib/multipart_app.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'dart:developer';
23
import 'dart:io';
34
import 'dart:typed_data';
@@ -171,8 +172,8 @@ class RemoveBgApiInterceptor extends InterceptorContract {
171172
}
172173

173174
@override
174-
Future<BaseResponse> interceptResponse({
175+
BaseResponse interceptResponse({
175176
required BaseResponse response,
176-
}) async =>
177+
}) =>
177178
response;
178179
}

Diff for: example/lib/weather_app.dart

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'dart:convert';
23
import 'dart:developer';
34
import 'dart:io';
@@ -267,15 +268,15 @@ class WeatherRepository {
267268
// var parsedWeather;
268269
// try {
269270
// var response = await InterceptedHttp.build(
270-
// interceptors: [WeatherApiInterceptor()])
271-
// .get("$baseUrl/weather", params: {'id': "$id"});
271+
// interceptors: [WeatherApiInterceptor()],
272+
// ).get('$baseUrl/weather', params: {'id': '$id'});
272273
// if (response.statusCode == 200) {
273274
// parsedWeather = json.decode(response.body);
274275
// } else {
275-
// throw Exception("Error while fetching. \n ${response.body}");
276+
// throw Exception('Error while fetching. \n ${response.body}');
276277
// }
277278
// } catch (e) {
278-
// log(e);
279+
// log(e.toString());
279280
// }
280281
// return parsedWeather;
281282
// }
@@ -326,8 +327,9 @@ class WeatherApiInterceptor extends InterceptorContract {
326327
}
327328

328329
@override
329-
Future<BaseResponse> interceptResponse(
330-
{required BaseResponse response}) async =>
330+
BaseResponse interceptResponse({
331+
required BaseResponse response,
332+
}) =>
331333
response;
332334
}
333335

Diff for: lib/extensions/multipart_request.dart

+23-12
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,27 @@ extension MultipartRequestCopyWith on MultipartRequest {
1414
bool? followRedirects,
1515
int? maxRedirects,
1616
bool? persistentConnection,
17-
}) =>
18-
MultipartRequest(
19-
method?.asString ?? this.method,
20-
url ?? this.url,
21-
)
22-
..headers.addAll(headers ?? this.headers)
23-
..fields.addAll(fields ?? this.fields)
24-
..files.addAll(files ?? this.files)
25-
..followRedirects = followRedirects ?? this.followRedirects
26-
..maxRedirects = maxRedirects ?? this.maxRedirects
27-
..persistentConnection =
28-
persistentConnection ?? this.persistentConnection;
17+
}) {
18+
var clonedRequest =
19+
MultipartRequest(method?.asString ?? this.method, url ?? this.url)
20+
..headers.addAll(headers ?? this.headers)
21+
..fields.addAll(fields ?? this.fields);
22+
23+
for (var file in this.files) {
24+
clonedRequest.files.add(MultipartFile(
25+
file.field,
26+
file.finalize(),
27+
file.length,
28+
filename: file.filename,
29+
contentType: file.contentType,
30+
));
31+
}
32+
33+
this.persistentConnection =
34+
persistentConnection ?? this.persistentConnection;
35+
this.followRedirects = followRedirects ?? this.followRedirects;
36+
this.maxRedirects = maxRedirects ?? this.maxRedirects;
37+
38+
return clonedRequest;
39+
}
2940
}

Diff for: lib/extensions/streamed_request.dart

+20-18
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@ extension StreamedRequestCopyWith on StreamedRequest {
1414
int? maxRedirects,
1515
bool? persistentConnection,
1616
}) {
17-
final req = StreamedRequest(
18-
method?.asString ?? this.method,
19-
url ?? this.url,
20-
)
21-
..headers.addAll(headers ?? this.headers)
22-
..followRedirects = followRedirects ?? this.followRedirects
23-
..maxRedirects = maxRedirects ?? this.maxRedirects
24-
..persistentConnection =
25-
persistentConnection ?? this.persistentConnection;
17+
// Create a new StreamedRequest with the same method and URL
18+
var clonedRequest =
19+
StreamedRequest(method?.asString ?? this.method, url ?? this.url)
20+
..headers.addAll(headers ?? this.headers);
2621

27-
if (stream != null) {
28-
stream.listen((data) {
29-
req.sink.add(data);
30-
});
31-
finalize().listen((data) {
32-
req.sink.add(data);
33-
});
34-
}
22+
// Use a broadcast stream to allow multiple listeners
23+
var broadcastStream =
24+
stream?.asBroadcastStream() ?? finalize().asBroadcastStream();
3525

36-
return req;
26+
// Pipe the broadcast stream into the cloned request's sink
27+
broadcastStream.listen((data) {
28+
clonedRequest.sink.add(data);
29+
}, onDone: () {
30+
clonedRequest.sink.close();
31+
});
32+
33+
this.persistentConnection =
34+
persistentConnection ?? this.persistentConnection;
35+
this.followRedirects = followRedirects ?? this.followRedirects;
36+
this.maxRedirects = maxRedirects ?? this.maxRedirects;
37+
38+
return clonedRequest;
3739
}
3840
}

Diff for: lib/http/intercepted_client.dart

+7-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,13 @@ class InterceptedClient extends BaseClient {
219219

220220
final interceptedResponse = await _interceptResponse(response);
221221

222-
return interceptedResponse as StreamedResponse;
222+
if (interceptedResponse is StreamedResponse) {
223+
return interceptedResponse;
224+
}
225+
226+
throw ClientException(
227+
'Expected `StreamedResponse`, got ${interceptedResponse.runtimeType}.',
228+
);
223229
}
224230

225231
Future<BaseResponse> _sendUnstreamed({

Diff for: lib/models/interceptor_contract.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import 'package:http/http.dart';
1414
///```dart
1515
/// class LoggingInterceptor implements InterceptorContract {
1616
/// @override
17-
/// Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
17+
/// FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
1818
/// print(request.toString());
1919
/// return data;
2020
/// }
2121
///
2222
/// @override
23-
/// Future<BaseResponse> interceptResponse({required BaseResponse response}) async {
23+
/// FutureOr<BaseResponse> interceptResponse({required BaseResponse response}) async {
2424
/// print(response.toString());
2525
/// return data;
2626
/// }

0 commit comments

Comments
 (0)