Skip to content

Commit 83da445

Browse files
authored
feat: adds request data to response data (#85)
* feat: adds request data to response data class * docs: adds documentation for request and response data * build: version bump * docs: update changelog
1 parent 12c3cb9 commit 83da445

File tree

7 files changed

+132
-36
lines changed

7 files changed

+132
-36
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 1.0.1
4+
5+
-  Changed: `ResponseData` now has `request` to allow checking on the request that triggered the response. Thanks to @II11II
6+
- 🐞  Fixed: Use `queryParametersAll` when creating `RequestData`. Thanks to @Mawi137
7+
- 📖  Fixed: `README` to include `required` keywords needed. Thanks to @meysammahfouzi
8+
- 🚦  Tests: Improved testing and documentation.
9+
310
## 1.0.0
411

512
Check out the [1.0.0 migration guide](./guides/migration_guide_1.0.0.md) for information on how to migrate your code.

lib/http/intercepted_client.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class InterceptedClient extends BaseClient {
169169
});
170170
}
171171

172-
// TODO: Implement interception from `send` method.
172+
// TODO(codingalecr): Implement interception from `send` method.
173173
@override
174174
Future<StreamedResponse> send(BaseRequest request) {
175175
return _inner.send(request);

lib/models/request_data.dart

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,28 @@ import 'package:http_interceptor/extensions/extensions.dart';
55
import 'package:http_interceptor/http/http.dart';
66
import 'package:http_interceptor/utils/utils.dart';
77

8+
/// A class that mimics HTTP Request in order to intercept it's data.
89
class RequestData {
10+
/// The HTTP method of the request.
11+
///
12+
/// Most commonly "GET" or "POST", less commonly "HEAD", "PUT", or "DELETE".
13+
/// Non-standard method names are also supported.
914
Method method;
15+
16+
/// The base URL String to which the request will be sent. It does not include
17+
/// the query parameters.
1018
String baseUrl;
19+
20+
/// Map of String to String that represents the headers of the request.
1121
Map<String, String> headers;
22+
23+
/// Map of String to String that represents the query parameters of the
24+
/// request.
1225
Map<String, dynamic> params;
13-
dynamic? body;
26+
27+
dynamic body;
28+
29+
/// The encoding used for the request.
1430
Encoding? encoding;
1531

1632
RequestData({
@@ -23,24 +39,38 @@ class RequestData {
2339
}) : headers = headers ?? {},
2440
params = params ?? {};
2541

42+
/// The complete URL String including query parameters to which the request
43+
/// will be sent.
2644
String get url => buildUrlString(baseUrl, params);
2745

28-
factory RequestData.fromHttpRequest(Request request) {
46+
/// Creates a new request data from an HTTP request.
47+
///
48+
/// For now it only supports [Request].
49+
/// TODO(codingalecr): Support for [MultipartRequest] and [StreamedRequest].
50+
factory RequestData.fromHttpRequest(BaseRequest request) {
2951
var params = Map<String, dynamic>();
3052
request.url.queryParametersAll.forEach((key, value) {
3153
params[key] = value;
3254
});
3355
String baseUrl = request.url.origin + request.url.path;
34-
return RequestData(
35-
method: methodFromString(request.method),
36-
encoding: request.encoding,
37-
body: request.body,
38-
baseUrl: baseUrl,
39-
headers: request.headers,
40-
params: params,
56+
57+
if (request is Request) {
58+
return RequestData(
59+
method: methodFromString(request.method),
60+
baseUrl: baseUrl,
61+
headers: request.headers,
62+
body: request.body,
63+
encoding: request.encoding,
64+
params: params,
65+
);
66+
}
67+
68+
throw UnsupportedError(
69+
"Can't intercept ${request.runtimeType}. Request type not supported yet.",
4170
);
4271
}
4372

73+
/// Converts this request data to an HTTP request.
4474
Request toHttpRequest() {
4575
var reqUrl = buildUrlString(baseUrl, params);
4676

@@ -50,7 +80,7 @@ class RequestData {
5080
if (encoding != null) request.encoding = encoding!;
5181
if (body != null) {
5282
if (body is String) {
53-
request.body = body;
83+
request.body = body as String;
5484
} else if (body is List) {
5585
request.bodyBytes = body?.cast<int>();
5686
} else if (body is Map) {
@@ -63,6 +93,7 @@ class RequestData {
6393
return request;
6494
}
6595

96+
/// Convenient toString implementation for logging.
6697
@override
6798
String toString() {
6899
return 'Request Data { $method, $baseUrl, $headers, $params, $body }';

lib/models/response_data.dart

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,83 @@ import 'dart:typed_data';
22

33
import 'package:http/http.dart';
44
import 'package:http_interceptor/http/http.dart';
5+
import 'package:http_interceptor/models/request_data.dart';
56

7+
/// A class that mimics HTTP Response in order to intercept it's data.
68
class ResponseData {
7-
String? url;
8-
int? statusCode;
9-
Method? method;
9+
/// The bytes comprising the body of this response.
10+
Uint8List bodyBytes;
11+
12+
/// The HTTP status code for this response.
13+
int statusCode;
14+
1015
Map<String, String>? headers;
16+
17+
/// The body of the response as a string.
1118
String? body;
1219

13-
/// The bytes comprising the body of this response.
14-
Uint8List bodyBytes;
20+
/// The size of the response body, in bytes.
21+
///
22+
/// If the size of the request is not known in advance, this is `null`.
1523
int? contentLength;
24+
1625
bool? isRedirect;
26+
27+
/// Whether the server requested that a persistent connection be maintained.
1728
bool? persistentConnection;
1829

19-
ResponseData({
20-
this.method,
21-
this.url,
22-
this.statusCode,
30+
/// The (frozen) request that triggered this response.
31+
RequestData? request;
32+
33+
/// Creates a new response data with body bytes.
34+
ResponseData(
35+
this.bodyBytes,
36+
this.statusCode, {
2337
this.headers,
2438
this.body,
25-
required this.bodyBytes,
2639
this.contentLength,
2740
this.isRedirect,
2841
this.persistentConnection,
42+
this.request,
2943
});
3044

45+
/// Method of the request that triggered this response.
46+
Method? get method => request?.method;
47+
48+
/// URL as String of the request that triggered this response.
49+
String? get url => request?.url;
50+
51+
/// Creates a new response data from an HTTP response.
3152
factory ResponseData.fromHttpResponse(Response response) {
3253
return ResponseData(
33-
statusCode: response.statusCode,
54+
response.bodyBytes,
55+
response.statusCode,
3456
headers: response.headers,
3557
body: response.body,
36-
bodyBytes: response.bodyBytes,
3758
contentLength: response.contentLength,
3859
isRedirect: response.isRedirect,
39-
url: response.request!.url.toString(),
40-
method: methodFromString(response.request!.method),
4160
persistentConnection: response.persistentConnection,
61+
request: (response.request != null)
62+
? RequestData.fromHttpRequest(response.request!)
63+
: null,
4264
);
4365
}
4466

67+
/// Converts this response data to an HTTP response.
4568
Response toHttpResponse() {
4669
return Response.bytes(
4770
bodyBytes,
48-
statusCode!,
71+
statusCode,
4972
headers: headers!,
5073
persistentConnection: persistentConnection!,
5174
isRedirect: isRedirect!,
52-
request: Request(
53-
methodToString(method!),
54-
Uri.parse(url!),
55-
),
75+
request: request?.toHttpRequest(),
5676
);
5777
}
5878

79+
/// Convenient toString implementation for logging.
5980
@override
6081
String toString() {
61-
return 'ResponseData { $method, $url, $headers, $statusCode, $body }';
82+
return 'ResponseData { $method, $url, $headers, $statusCode, $body, $request }';
6283
}
6384
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: http_interceptor
22
description: A lightweight, simple plugin that allows you to intercept request and response objects and modify them if desired.
3-
version: 1.0.0
3+
version: 1.0.1
44
homepage: https://github.com/CodingAleCR/http_interceptor
55
issue_tracker: https://github.com/CodingAleCR/http_interceptor/issues
66
repository: https://github.com/CodingAleCR/http_interceptor
Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,56 @@
11
import 'dart:typed_data';
22

3+
import 'package:http/http.dart';
34
import 'package:test/test.dart';
45
import 'package:http_interceptor/models/response_data.dart';
56

67
main() {
78
group("Initialization", () {
89
test("ResponseData can be instantiated", () {
910
// Arrange
10-
ResponseData requestData;
11+
ResponseData responseData;
1112

1213
// Act
13-
requestData = ResponseData(bodyBytes: Uint8List(0));
14+
responseData = ResponseData(Uint8List(0), 200);
1415

1516
// Assert
16-
expect(requestData, isNotNull);
17+
expect(responseData, isNotNull);
18+
});
19+
20+
test("ResponseData can be instantiated from HTTP Response", () {
21+
// Arrange
22+
final response = Response("Empty Body", 200);
23+
ResponseData responseData;
24+
25+
// Act
26+
responseData = ResponseData.fromHttpResponse(response);
27+
28+
// Assert
29+
expect(responseData, isNotNull);
30+
});
31+
test("ResponseData can all properties from HTTP Response", () {
32+
// Arrange
33+
Uri url = Uri.parse(
34+
"https://www.google.com/helloworld?key=123ABC&name=Hugo&type=3");
35+
36+
Request request = Request("GET", url);
37+
Response response = Response("Empty Body", 200, request: request);
38+
ResponseData responseData;
39+
40+
// Act
41+
responseData = ResponseData.fromHttpResponse(response);
42+
43+
// Assert
44+
expect(responseData, isNotNull);
45+
expect(responseData.request, isNotNull);
46+
expect(responseData.body, isNotNull);
47+
expect(responseData.bodyBytes, isNotNull);
48+
expect(responseData.statusCode, isNotNull);
49+
expect(responseData.url, equals(response.request!.url.toString()));
50+
expect(responseData.isRedirect, equals(response.isRedirect));
51+
expect(responseData.persistentConnection,
52+
equals(response.persistentConnection));
53+
expect(responseData.headers, equals(response.headers));
1754
});
1855
});
1956
}

test/models/retry_policy_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ main() {
2929
test("returns false by default", () async {
3030
expect(
3131
await testObject.shouldAttemptRetryOnResponse(
32-
ResponseData(bodyBytes: Uint8List(0)),
32+
ResponseData(Uint8List(0), 200),
3333
),
3434
false,
3535
);

0 commit comments

Comments
 (0)