Skip to content

Commit 2364df3

Browse files
authored
feat: add interceptError + refactor old Dart code (#159)
* 🚧 WIP intercept error * 🚧 WIP intercept error * ♻️ refactor intercepted_client * 🎨 facelift code * 🎨 facelift code * 🔀 resolve merge conflicts * 🚨 fix linter errors * ✅ add tests for error interception in `InterceptedClient` * ✅ add comprehensive tests for `InterceptedClient` covering factory methods, HTTP methods, interception, retries, and timeout handling * 🔥 remove unused test file `http_interceptor_test.dart` * ✅ add tests for `HttpMethod` covering OPTIONS support and `toString()` representation
1 parent 260c882 commit 2364df3

20 files changed

+1328
-332
lines changed

example/lib/common.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,26 @@ class LoggerInterceptor extends InterceptorContract {
2626
}
2727
return response;
2828
}
29+
30+
@override
31+
void interceptError({
32+
BaseRequest? request,
33+
BaseResponse? response,
34+
Exception? error,
35+
StackTrace? stackTrace,
36+
}) {
37+
log('----- Error -----');
38+
if (request != null) {
39+
log('Request: ${request.toString()}');
40+
}
41+
if (response != null) {
42+
log('Response: ${response.toString()}');
43+
}
44+
if (error != null) {
45+
log('Error: ${error.toString()}');
46+
}
47+
if (stackTrace != null) {
48+
log('StackTrace: $stackTrace');
49+
}
50+
}
2951
}

lib/extensions/base_request.dart

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,42 +33,39 @@ extension BaseRequestCopyWith on BaseRequest {
3333
List<MultipartFile>? files,
3434
// StreamedRequest only properties.
3535
Stream<List<int>>? stream,
36-
}) {
37-
if (this is Request) {
38-
return RequestCopyWith(this as Request).copyWith(
39-
method: method,
40-
url: url,
41-
headers: headers,
42-
body: body,
43-
encoding: encoding,
44-
followRedirects: followRedirects,
45-
maxRedirects: maxRedirects,
46-
persistentConnection: persistentConnection,
47-
);
48-
} else if (this is StreamedRequest) {
49-
return StreamedRequestCopyWith(this as StreamedRequest).copyWith(
50-
method: method,
51-
url: url,
52-
headers: headers,
53-
stream: stream,
54-
followRedirects: followRedirects,
55-
maxRedirects: maxRedirects,
56-
persistentConnection: persistentConnection,
57-
);
58-
} else if (this is MultipartRequest) {
59-
return MultipartRequestCopyWith(this as MultipartRequest).copyWith(
60-
method: method,
61-
url: url,
62-
headers: headers,
63-
fields: fields,
64-
files: files,
65-
followRedirects: followRedirects,
66-
maxRedirects: maxRedirects,
67-
persistentConnection: persistentConnection,
68-
);
69-
}
70-
71-
throw UnsupportedError(
72-
'Cannot copy unsupported type of request $runtimeType');
73-
}
36+
}) =>
37+
switch (this) {
38+
Request req => req.copyWith(
39+
method: method,
40+
url: url,
41+
headers: headers,
42+
body: body,
43+
encoding: encoding,
44+
followRedirects: followRedirects,
45+
maxRedirects: maxRedirects,
46+
persistentConnection: persistentConnection,
47+
),
48+
StreamedRequest req => req.copyWith(
49+
method: method,
50+
url: url,
51+
headers: headers,
52+
stream: stream,
53+
followRedirects: followRedirects,
54+
maxRedirects: maxRedirects,
55+
persistentConnection: persistentConnection,
56+
),
57+
MultipartRequest req => req.copyWith(
58+
method: method,
59+
url: url,
60+
headers: headers,
61+
fields: fields,
62+
files: files,
63+
followRedirects: followRedirects,
64+
maxRedirects: maxRedirects,
65+
persistentConnection: persistentConnection,
66+
),
67+
_ => throw UnsupportedError(
68+
'Cannot copy unsupported type of request $runtimeType',
69+
),
70+
};
7471
}

lib/extensions/base_response_io.dart

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,43 +32,40 @@ extension BaseResponseCopyWith on BaseResponse {
3232
int? contentLength,
3333
// `IOStreamedResponse` only properties.
3434
HttpClientResponse? inner,
35-
}) {
36-
if (this is Response) {
37-
return ResponseCopyWith(this as Response).copyWith(
38-
statusCode: statusCode,
39-
body: body,
40-
request: request,
41-
headers: headers,
42-
isRedirect: isRedirect,
43-
persistentConnection: persistentConnection,
44-
reasonPhrase: reasonPhrase,
45-
);
46-
} else if (this is StreamedResponse) {
47-
return StreamedResponseCopyWith(this as StreamedResponse).copyWith(
48-
stream: stream,
49-
statusCode: statusCode,
50-
contentLength: contentLength,
51-
request: request,
52-
headers: headers,
53-
isRedirect: isRedirect,
54-
persistentConnection: persistentConnection,
55-
reasonPhrase: reasonPhrase,
56-
);
57-
} else if (this is IOStreamedResponse) {
58-
return IOStreamedResponseCopyWith(this as IOStreamedResponse).copyWith(
59-
stream: stream,
60-
statusCode: statusCode,
61-
contentLength: contentLength,
62-
request: request,
63-
headers: headers,
64-
isRedirect: isRedirect,
65-
persistentConnection: persistentConnection,
66-
reasonPhrase: reasonPhrase,
67-
inner: inner,
68-
);
69-
}
70-
71-
throw UnsupportedError(
72-
'Cannot copy unsupported type of response $runtimeType');
73-
}
35+
}) =>
36+
switch (this) {
37+
Response res => res.copyWith(
38+
statusCode: statusCode,
39+
body: body,
40+
request: request,
41+
headers: headers,
42+
isRedirect: isRedirect,
43+
persistentConnection: persistentConnection,
44+
reasonPhrase: reasonPhrase,
45+
),
46+
IOStreamedResponse res => res.copyWith(
47+
stream: stream,
48+
statusCode: statusCode,
49+
contentLength: contentLength,
50+
request: request,
51+
headers: headers,
52+
isRedirect: isRedirect,
53+
persistentConnection: persistentConnection,
54+
reasonPhrase: reasonPhrase,
55+
inner: inner,
56+
),
57+
StreamedResponse res => res.copyWith(
58+
stream: stream,
59+
statusCode: statusCode,
60+
contentLength: contentLength,
61+
request: request,
62+
headers: headers,
63+
isRedirect: isRedirect,
64+
persistentConnection: persistentConnection,
65+
reasonPhrase: reasonPhrase,
66+
),
67+
_ => throw UnsupportedError(
68+
'Cannot copy unsupported type of response $runtimeType',
69+
),
70+
};
7471
}

lib/extensions/base_response_none.dart

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,29 @@ extension BaseResponseCopyWith on BaseResponse {
2424
// `StreamedResponse` only properties.
2525
Stream<List<int>>? stream,
2626
int? contentLength,
27-
}) {
28-
if (this is Response) {
29-
return ResponseCopyWith(this as Response).copyWith(
30-
statusCode: statusCode,
31-
body: body,
32-
request: request,
33-
headers: headers,
34-
isRedirect: isRedirect,
35-
persistentConnection: persistentConnection,
36-
reasonPhrase: reasonPhrase,
37-
);
38-
} else if (this is StreamedResponse) {
39-
return StreamedResponseCopyWith(this as StreamedResponse).copyWith(
40-
stream: stream,
41-
statusCode: statusCode,
42-
contentLength: contentLength,
43-
request: request,
44-
headers: headers,
45-
isRedirect: isRedirect,
46-
persistentConnection: persistentConnection,
47-
reasonPhrase: reasonPhrase,
48-
);
49-
}
50-
51-
throw UnsupportedError(
52-
'Cannot copy unsupported type of response $runtimeType');
53-
}
27+
}) =>
28+
switch (this) {
29+
Response res => res.copyWith(
30+
statusCode: statusCode,
31+
body: body,
32+
request: request,
33+
headers: headers,
34+
isRedirect: isRedirect,
35+
persistentConnection: persistentConnection,
36+
reasonPhrase: reasonPhrase,
37+
),
38+
StreamedResponse res => res.copyWith(
39+
stream: stream,
40+
statusCode: statusCode,
41+
contentLength: contentLength,
42+
request: request,
43+
headers: headers,
44+
isRedirect: isRedirect,
45+
persistentConnection: persistentConnection,
46+
reasonPhrase: reasonPhrase,
47+
),
48+
_ => throw UnsupportedError(
49+
'Cannot copy unsupported type of response $runtimeType',
50+
),
51+
};
5452
}

lib/extensions/io_streamed_response.dart

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@ extension IOStreamedResponseCopyWith on IOStreamedResponse {
1414
bool? persistentConnection,
1515
String? reasonPhrase,
1616
HttpClientResponse? inner,
17-
}) {
18-
return IOStreamedResponse(
19-
stream ?? this.stream,
20-
statusCode ?? this.statusCode,
21-
contentLength: contentLength ?? this.contentLength,
22-
request: request ?? this.request,
23-
headers: headers ?? this.headers,
24-
isRedirect: isRedirect ?? this.isRedirect,
25-
persistentConnection: persistentConnection ?? this.persistentConnection,
26-
reasonPhrase: reasonPhrase ?? this.reasonPhrase,
27-
inner: inner,
28-
);
29-
}
17+
}) =>
18+
IOStreamedResponse(
19+
stream ?? this.stream,
20+
statusCode ?? this.statusCode,
21+
contentLength: contentLength ?? this.contentLength,
22+
request: request ?? this.request,
23+
headers: headers ?? this.headers,
24+
isRedirect: isRedirect ?? this.isRedirect,
25+
persistentConnection: persistentConnection ?? this.persistentConnection,
26+
reasonPhrase: reasonPhrase ?? this.reasonPhrase,
27+
inner: inner,
28+
);
3029
}

lib/extensions/multipart_request.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ extension MultipartRequestCopyWith on MultipartRequest {
1515
int? maxRedirects,
1616
bool? persistentConnection,
1717
}) {
18-
var clonedRequest =
18+
final MultipartRequest clonedRequest =
1919
MultipartRequest(method?.asString ?? this.method, url ?? this.url)
2020
..headers.addAll(headers ?? this.headers)
2121
..fields.addAll(fields ?? this.fields);
2222

23-
for (var file in this.files) {
23+
for (final MultipartFile file in this.files) {
2424
clonedRequest.files.add(MultipartFile(
2525
file.field,
2626
file.finalize(),

lib/extensions/request.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extension RequestCopyWith on Request {
1818
int? maxRedirects,
1919
bool? persistentConnection,
2020
}) {
21-
final copied = Request(
21+
final Request copied = Request(
2222
method?.asString ?? this.method,
2323
url ?? this.url,
2424
)..bodyBytes = this.bodyBytes;

lib/extensions/streamed_request.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,19 @@ extension StreamedRequestCopyWith on StreamedRequest {
1515
bool? persistentConnection,
1616
}) {
1717
// Create a new StreamedRequest with the same method and URL
18-
var clonedRequest =
18+
final StreamedRequest clonedRequest =
1919
StreamedRequest(method?.asString ?? this.method, url ?? this.url)
2020
..headers.addAll(headers ?? this.headers);
2121

2222
// Use a broadcast stream to allow multiple listeners
23-
var broadcastStream =
23+
final Stream<List<int>> broadcastStream =
2424
stream?.asBroadcastStream() ?? finalize().asBroadcastStream();
2525

2626
// 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-
});
27+
broadcastStream.listen(
28+
(List<int> data) => clonedRequest.sink.add(data),
29+
onDone: () => clonedRequest.sink.close(),
30+
);
3231

3332
this.persistentConnection =
3433
persistentConnection ?? this.persistentConnection;

lib/extensions/uri.dart

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,23 @@
11
import 'package:http_interceptor/extensions/string.dart';
22
import 'package:http_interceptor/utils/utils.dart';
33

4-
/// Extends `Uri` to allow adding parameters to already created intstances
4+
/// Extends `Uri` to allow adding parameters to already created instances.
55
extension AddParameters on Uri {
6-
/// Returns a new `Uri` instance based on `this` and adds [parameters].
7-
Uri addParameters(Map<String, dynamic>? parameters) {
8-
if (parameters == null) return this;
9-
10-
String paramUrl = origin + path;
11-
12-
Map<String, dynamic> newParameters = {};
13-
14-
queryParametersAll.forEach((key, values) {
15-
newParameters[key] = values;
16-
});
17-
18-
parameters.forEach((key, value) {
19-
newParameters[key] = value;
20-
});
21-
22-
String finalUrl = buildUrlString(paramUrl, newParameters);
23-
24-
// Preserve the fragment if it exists
25-
if (fragment.isNotEmpty) {
26-
finalUrl += '#$fragment';
27-
}
28-
29-
return finalUrl.toUri();
30-
}
6+
/// Returns a new [Uri] instance based on `this` and adds [parameters].
7+
Uri addParameters([Map<String, dynamic>? parameters]) =>
8+
parameters?.isNotEmpty ?? false
9+
? (StringBuffer()
10+
..writeAll([
11+
buildUrlString(
12+
"$origin$path",
13+
{
14+
...queryParametersAll,
15+
...?parameters,
16+
},
17+
),
18+
if (fragment.isNotEmpty) '#$fragment',
19+
]))
20+
.toString()
21+
.toUri()
22+
: this;
3123
}

0 commit comments

Comments
 (0)