Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update docs and improve multipart support #150

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,26 @@ import 'package:http_interceptor/http_interceptor.dart';

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.

`interceptRequest` and `interceptResponse` use `FutureOr` syntax, which makes it easier to support both synchronous and asynchronous behaviors.

- Logging with interceptor:

```dart
class LoggerInterceptor extends InterceptorContract {
@override
Future<BaseRequest> interceptRequest({
BaseRequest interceptRequest({
required BaseRequest request,
}) async {
}) {
print('----- Request -----');
print(request.toString());
print(request.headers.toString());
return request;
}

@override
Future<BaseResponse> interceptResponse({
BaseResponse interceptResponse({
required BaseResponse response,
}) async {
}) {
log('----- Response -----');
log('Code: ${response.statusCode}');
if (response is Response) {
Expand All @@ -102,7 +104,7 @@ class LoggerInterceptor extends InterceptorContract {
```dart
class WeatherApiInterceptor implements InterceptorContract {
@override
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
try {
request.url.queryParameters['appid'] = OPEN_WEATHER_API_KEY;
request.url.queryParameters['units'] = 'metric';
Expand All @@ -114,7 +116,10 @@ class WeatherApiInterceptor implements InterceptorContract {
}

@override
Future<BaseResponse> interceptResponse({required BaseResponse response}) async => response;
BaseResponse interceptResponse({
required BaseResponse response,
}) =>
response;
}
```

Expand All @@ -123,15 +128,15 @@ class WeatherApiInterceptor implements InterceptorContract {
```dart
class MultipartRequestInterceptor implements InterceptorContract {
@override
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
if(request is MultipartRequest){
request.fields['app_version'] = await PackageInfo.fromPlatform().version;
}
return request;
}

@override
Future<BaseResponse> interceptResponse({required BaseResponse response}) async {
FutureOr<BaseResponse> interceptResponse({required BaseResponse response}) async {
if(response is StreamedResponse){
response.stream.asBroadcastStream().listen((data){
print(data);
Expand Down
8 changes: 4 additions & 4 deletions example/lib/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import 'package:http_interceptor/http_interceptor.dart';

class LoggerInterceptor extends InterceptorContract {
@override
Future<BaseRequest> interceptRequest({
BaseRequest interceptRequest({
required BaseRequest request,
}) async {
}) {
log('----- Request -----');
log(request.toString());
log(request.headers.toString());
Expand All @@ -15,9 +15,9 @@ class LoggerInterceptor extends InterceptorContract {
}

@override
Future<BaseResponse> interceptResponse({
BaseResponse interceptResponse({
required BaseResponse response,
}) async {
}) {
log('----- Response -----');
log('Code: ${response.statusCode}');
log('Response type: ${response.runtimeType}');
Expand Down
5 changes: 3 additions & 2 deletions example/lib/multipart_app.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'dart:typed_data';
Expand Down Expand Up @@ -171,8 +172,8 @@ class RemoveBgApiInterceptor extends InterceptorContract {
}

@override
Future<BaseResponse> interceptResponse({
BaseResponse interceptResponse({
required BaseResponse response,
}) async =>
}) =>
response;
}
14 changes: 8 additions & 6 deletions example/lib/weather_app.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
Expand Down Expand Up @@ -267,15 +268,15 @@ class WeatherRepository {
// var parsedWeather;
// try {
// var response = await InterceptedHttp.build(
// interceptors: [WeatherApiInterceptor()])
// .get("$baseUrl/weather", params: {'id': "$id"});
// interceptors: [WeatherApiInterceptor()],
// ).get('$baseUrl/weather', params: {'id': '$id'});
// if (response.statusCode == 200) {
// parsedWeather = json.decode(response.body);
// } else {
// throw Exception("Error while fetching. \n ${response.body}");
// throw Exception('Error while fetching. \n ${response.body}');
// }
// } catch (e) {
// log(e);
// log(e.toString());
// }
// return parsedWeather;
// }
Expand Down Expand Up @@ -326,8 +327,9 @@ class WeatherApiInterceptor extends InterceptorContract {
}

@override
Future<BaseResponse> interceptResponse(
{required BaseResponse response}) async =>
BaseResponse interceptResponse({
required BaseResponse response,
}) =>
response;
}

Expand Down
35 changes: 23 additions & 12 deletions lib/extensions/multipart_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,27 @@ extension MultipartRequestCopyWith on MultipartRequest {
bool? followRedirects,
int? maxRedirects,
bool? persistentConnection,
}) =>
MultipartRequest(
method?.asString ?? this.method,
url ?? this.url,
)
..headers.addAll(headers ?? this.headers)
..fields.addAll(fields ?? this.fields)
..files.addAll(files ?? this.files)
..followRedirects = followRedirects ?? this.followRedirects
..maxRedirects = maxRedirects ?? this.maxRedirects
..persistentConnection =
persistentConnection ?? this.persistentConnection;
}) {
var clonedRequest =
MultipartRequest(method?.asString ?? this.method, url ?? this.url)
..headers.addAll(headers ?? this.headers)
..fields.addAll(fields ?? this.fields);

for (var file in this.files) {
clonedRequest.files.add(MultipartFile(
file.field,
file.finalize(),
file.length,
filename: file.filename,
contentType: file.contentType,
));
}

this.persistentConnection =
persistentConnection ?? this.persistentConnection;
this.followRedirects = followRedirects ?? this.followRedirects;
this.maxRedirects = maxRedirects ?? this.maxRedirects;

return clonedRequest;
}
}
38 changes: 20 additions & 18 deletions lib/extensions/streamed_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,27 @@ extension StreamedRequestCopyWith on StreamedRequest {
int? maxRedirects,
bool? persistentConnection,
}) {
final req = StreamedRequest(
method?.asString ?? this.method,
url ?? this.url,
)
..headers.addAll(headers ?? this.headers)
..followRedirects = followRedirects ?? this.followRedirects
..maxRedirects = maxRedirects ?? this.maxRedirects
..persistentConnection =
persistentConnection ?? this.persistentConnection;
// Create a new StreamedRequest with the same method and URL
var clonedRequest =
StreamedRequest(method?.asString ?? this.method, url ?? this.url)
..headers.addAll(headers ?? this.headers);

if (stream != null) {
stream.listen((data) {
req.sink.add(data);
});
finalize().listen((data) {
req.sink.add(data);
});
}
// Use a broadcast stream to allow multiple listeners
var broadcastStream =
stream?.asBroadcastStream() ?? finalize().asBroadcastStream();

return req;
// Pipe the broadcast stream into the cloned request's sink
broadcastStream.listen((data) {
clonedRequest.sink.add(data);
}, onDone: () {
clonedRequest.sink.close();
});

this.persistentConnection =
persistentConnection ?? this.persistentConnection;
this.followRedirects = followRedirects ?? this.followRedirects;
this.maxRedirects = maxRedirects ?? this.maxRedirects;

return clonedRequest;
}
}
8 changes: 7 additions & 1 deletion lib/http/intercepted_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,13 @@ class InterceptedClient extends BaseClient {

final interceptedResponse = await _interceptResponse(response);

return interceptedResponse as StreamedResponse;
if (interceptedResponse is StreamedResponse) {
return interceptedResponse;
}

throw ClientException(
'Expected `StreamedResponse`, got ${interceptedResponse.runtimeType}.',
);
}

Future<BaseResponse> _sendUnstreamed({
Expand Down
4 changes: 2 additions & 2 deletions lib/models/interceptor_contract.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import 'package:http/http.dart';
///```dart
/// class LoggingInterceptor implements InterceptorContract {
/// @override
/// Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
/// FutureOr<BaseRequest> interceptRequest({required BaseRequest request}) async {
/// print(request.toString());
/// return data;
/// }
///
/// @override
/// Future<BaseResponse> interceptResponse({required BaseResponse response}) async {
/// FutureOr<BaseResponse> interceptResponse({required BaseResponse response}) async {
/// print(response.toString());
/// return data;
/// }
Expand Down
Loading