Skip to content

Commit

Permalink
refactor: add inferContentType parameter to SturdyHttp constructor (#4)
Browse files Browse the repository at this point in the history
* refactor: add inferContentType parameter to SturdyHttp constructor

* run format

* add trailing comma

* clarify test names
  • Loading branch information
btrautmann authored Jul 19, 2023
1 parent aa9dd16 commit 3a709fa
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 8 deletions.
14 changes: 11 additions & 3 deletions lib/src/network_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,25 @@ class RawRequest extends NetworkRequest {
);
}

/// The body of a [NetworkRequest].
/// The body of a [NetworkRequest]. Note that this type is aimed at providing
/// readability and type safety and does not dictate behavior of [SturdyHttp]
/// with regards to the content-type header. If you want [SturdyHttp] to infer
/// the content-type header, configure this via the `inferContentType` parameter
/// when constructing the instance.
@Freezed(copyWith: false)
class NetworkRequestBody with _$NetworkRequestBody {
/// An empty body. Results in `null` being passed to `data` of the request.
const factory NetworkRequestBody.empty() = _Empty;

/// A JSON body. Passed directly to `data` of the request.
/// A JSON body. Passed directly to `data` of the request. If `inferContentType`
/// has been provided as `true` to the [SturdyHttp] instance, will result in
/// an `application-json` `content-type`.
const factory NetworkRequestBody.json(Json data) = _Json;

/// A raw body. Allows for nullable untyped data that is passed directly
/// to `data` of the request, useful for instances where the data type
/// is not known until runtime.
/// is not known until runtime. If `inferContentType` has been provided as
/// `true` to the [SturdyHttp] instance *and* the [data] can be used to infer
/// the `content-type` header, it will be inferred.
const factory NetworkRequestBody.raw(Object? data) = _Raw;
}
9 changes: 7 additions & 2 deletions lib/src/sturdy_http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ class SturdyHttp {
SturdyHttpEventListener? eventListener,
HttpClientAdapter? customAdapter,
Map<String, String>? proxy,
bool inferContentType = true,
}) : this._(
dio: _configureDio(
baseUrl: baseUrl,
deserializer: deserializer,
interceptors: interceptors,
customAdapter: customAdapter,
proxy: proxy,
inferContentType: inferContentType,
),
deserializer: deserializer,
eventListener: eventListener,
Expand Down Expand Up @@ -227,6 +229,7 @@ Dio _configureDio({
required Deserializer deserializer,
required HttpClientAdapter? customAdapter,
required Map<String, String>? proxy,
required bool inferContentType,
}) {
return Dio()
// Instruct Dio to use the same Isolate approach as requested of SturdyHttp
Expand All @@ -236,10 +239,12 @@ Dio _configureDio({
..options.baseUrl = baseUrl
..options.listFormat = ListFormat.multiCompatible
..interceptors.addAll(interceptors)
..interceptors.removeImplyContentTypeInterceptor()
..map((dio) {
if (customAdapter != null) {
return dio..httpClientAdapter = customAdapter;
dio.httpClientAdapter = customAdapter;
}
if (!inferContentType) {
dio.interceptors.removeImplyContentTypeInterceptor();
}
return dio;
});
Expand Down
71 changes: 68 additions & 3 deletions test/src/sturdy_http_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,80 @@ void main() {
String baseUrl = 'http://example.com',
List<Interceptor> interceptors = const [],
Map<String, String>? proxy,
bool inferContentType = false,
}) {
return SturdyHttp(
baseUrl: baseUrl,
customAdapter: charlatan.toFakeHttpClientAdapter(),
eventListener: eventListener,
interceptors: interceptors,
proxy: proxy,
inferContentType: inferContentType,
);
}

group('interceptors', () {
test('it returns the correct interceptors', () {
test('it returns the provided interceptors', () {
final interceptors = [_FakeInterceptor()];
final subject = buildSubject(interceptors: interceptors);
final subject = buildSubject(
interceptors: interceptors,
inferContentType: false,
);

expect(subject.interceptors, interceptors);
});
});

group('inferContentType', () {
test('it does not infer content-type when false', () async {
String? contentType;
final subject = buildSubject(
inferContentType: false,
interceptors: [
_FakeInterceptor(
onRequestInvoked: (options) {
contentType =
options.headers[Headers.contentTypeHeader] as String?;
},
)
],
);

charlatan.whenPost('/infer', (request) => null);

await subject.execute(
PostRequest('/infer', data: NetworkRequestBody.json({'foo': 'bar'})),
onResponse: (r) {},
);

expect(contentType, isNull);
});

test('it infers content-type when true', () async {
String? contentType;
final subject = buildSubject(
inferContentType: true,
interceptors: [
_FakeInterceptor(
onRequestInvoked: (options) {
contentType =
options.headers[Headers.contentTypeHeader] as String?;
},
)
],
);

charlatan.whenPost('/infer', (request) => null);

await subject.execute(
PostRequest('/infer', data: NetworkRequestBody.json({'foo': 'bar'})),
onResponse: (r) {},
);

expect(contentType, 'application/json');
});
});

group('baseUrl', () {
test('it returns the correct baseUrl', () {
const baseUrl = 'https://foo.com';
Expand Down Expand Up @@ -756,7 +811,17 @@ class Result<S, F> with _$Result<S, F> {
const factory Result.failure(F failure) = _Failure;
}

class _FakeInterceptor extends Interceptor {}
class _FakeInterceptor extends Interceptor {
final Function(RequestOptions options)? onRequestInvoked;

_FakeInterceptor({this.onRequestInvoked});

@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
onRequestInvoked?.call(options);
super.onRequest(options, handler);
}
}

class _SturdyHttpEventListener extends SturdyHttpEventListener {
final void Function(RequestOptions) onAuthFailure;
Expand Down

0 comments on commit 3a709fa

Please sign in to comment.