Skip to content
This repository has been archived by the owner on Feb 13, 2023. It is now read-only.

Commit

Permalink
Imply the default content type if capable (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexV525 authored Dec 21, 2022
1 parent 669c48b commit 2e63df2
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 38 deletions.
6 changes: 6 additions & 0 deletions dio/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 5.0.0-dev.2

- Revert the removal of `setRequestContentTypeWhenNoPayload`
and provide better conditions for the default `content-type` header.

## 5.0.0-dev.1

- Allow asynchronized method with `savePath`.
Expand All @@ -11,6 +16,7 @@

### Breaking Changes

- Remove `BaseOptions.setRequestContentTypeWhenNoPayload`.
- Improve `DioError`s. There are now more cases in which the inner original stacktrace is supplied.
- `HttpClientAdapter` must now be implemented instead of extended.
- Any classes specific to `dart:io` platforms can now be imported via `import 'package:diox/io.dart';`.
Expand Down
55 changes: 36 additions & 19 deletions dio/lib/src/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class BaseOptions extends _RequestConfig with OptionsMixin {
RequestEncoder? requestEncoder,
ResponseDecoder? responseDecoder,
ListFormat? listFormat,
this.setRequestContentTypeWhenNoPayload = false,
}) : assert(connectTimeout == null || !connectTimeout.isNegative),
assert(baseUrl.isEmpty || Uri.parse(baseUrl).host.isNotEmpty),
super(
Expand Down Expand Up @@ -144,6 +145,7 @@ class BaseOptions extends _RequestConfig with OptionsMixin {
RequestEncoder? requestEncoder,
ResponseDecoder? responseDecoder,
ListFormat? listFormat,
bool? setRequestContentTypeWhenNoPayload,
}) {
return BaseOptions(
method: method ?? this.method,
Expand All @@ -165,8 +167,19 @@ class BaseOptions extends _RequestConfig with OptionsMixin {
requestEncoder: requestEncoder ?? this.requestEncoder,
responseDecoder: responseDecoder ?? this.responseDecoder,
listFormat: listFormat ?? this.listFormat,
setRequestContentTypeWhenNoPayload: setRequestContentTypeWhenNoPayload ??
this.setRequestContentTypeWhenNoPayload,
);
}

/// The option will try to imply the default `content-type` header value
/// if there is a payload in requests and if the header value not set.
///
/// The `content-type` header value will be implied to
/// [Headers.jsonContentType] when:
/// - [RequestOptions.data] is null and the option is true.
/// - [RequestOptions.data] is not null.
bool setRequestContentTypeWhenNoPayload;
}

mixin OptionsMixin {
Expand Down Expand Up @@ -292,10 +305,14 @@ class Options {

final headers = caseInsensitiveKeyMap(baseOpt.headers);
headers.remove(Headers.contentTypeHeader);
if (this.headers != null) {
headers.addAll(this.headers!);
headers.addAll(this.headers ?? {});
// Imply the default content type if capable.
if (data != null ||
baseOpt.setRequestContentTypeWhenNoPayload && data == null) {
headers[Headers.contentTypeHeader] ??= Headers.jsonContentType;
}
final String? contentType = this.headers?[Headers.contentTypeHeader];
final String? contentType =
headers[Headers.contentTypeHeader] ?? this.contentType;
final extra = Map<String, dynamic>.from(baseOpt.extra);
if (this.extra != null) {
extra.addAll(this.extra!);
Expand Down Expand Up @@ -323,12 +340,11 @@ class Options {
requestEncoder: requestEncoder ?? baseOpt.requestEncoder,
responseDecoder: responseDecoder ?? baseOpt.responseDecoder,
listFormat: listFormat ?? baseOpt.listFormat,
onReceiveProgress: onReceiveProgress,
onSendProgress: onSendProgress,
cancelToken: cancelToken,
contentType: contentType ?? this.contentType ?? baseOpt.contentType,
);
requestOptions.onReceiveProgress = onReceiveProgress;
requestOptions.onSendProgress = onSendProgress;
requestOptions.cancelToken = cancelToken;
requestOptions.contentType =
contentType ?? this.contentType ?? baseOpt.contentType;
return requestOptions;
}

Expand Down Expand Up @@ -659,8 +675,8 @@ class _RequestConfig {

set headers(Map<String, dynamic>? headers) {
_headers = caseInsensitiveKeyMap(headers);
if (_defaultContentType != null &&
!_headers.containsKey(Headers.contentTypeHeader)) {
if (!_headers.containsKey(Headers.contentTypeHeader) &&
_defaultContentType != null) {
_headers[Headers.contentTypeHeader] = _defaultContentType;
}
}
Expand Down Expand Up @@ -698,24 +714,25 @@ class _RequestConfig {

Duration? _receiveTimeout;

/// The request Content-Type. The default value is [ContentType.json].
/// The request Content-Type. Defaults to [ContentType.json] if capable.
///
/// If you want to encode request body with 'application/x-www-form-urlencoded',
/// you can set `ContentType.parse('application/x-www-form-urlencoded')`, and [Dio]
/// will automatically encode the request body.
/// you can set `ContentType.parse('application/x-www-form-urlencoded')`,
/// and [Dio] will automatically encode the request body.
String? get contentType => _headers[Headers.contentTypeHeader] as String?;

set contentType(String? contentType) {
if (contentType != null) {
_headers[Headers.contentTypeHeader] =
_defaultContentType = contentType.trim();
final newContentType = contentType?.trim();
_defaultContentType = newContentType;
if (newContentType != null) {
_headers[Headers.contentTypeHeader] = newContentType;
} else {
_defaultContentType = null;
_headers.remove(Headers.contentTypeHeader);
}
}

String? _defaultContentType;

String? get contentType => _headers[Headers.contentTypeHeader] as String?;

/// [responseType] indicates the type of data that the server will respond with
/// options which defined in [ResponseType] are `json`, `stream`, `plain`.
///
Expand Down
2 changes: 0 additions & 2 deletions dio/migration_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ When new content need to be added to the migration guide, make sure they're foll

### Summary

- `BaseOptions.setRequestContentTypeWhenNoPayload` has been removed,
which will not imply `Content-Type` by default, and requests should explicitly define their content type.
- `get` and `getUri` in `Dio` has different signature.
- `DefaultHttpClientAdapter` is now named `IOHttpClientAdapter`,
and the platform independent adapter can be initiated by `HttpClientAdapter()` which is a factory method.
Expand Down
2 changes: 1 addition & 1 deletion dio/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: diox
description: A powerful Http client for Dart, which supports Interceptors, FormData, Request Cancellation, File Downloading, Timeout etc.
version: 5.0.0-dev.1
version: 5.0.0-dev.2
homepage: https://github.com/cfug/diox
repository: https://github.com/cfug/diox/blob/main/dio
issue_tracker: https://github.com/cfug/diox/issues
Expand Down
45 changes: 30 additions & 15 deletions dio/test/options_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,30 @@ void main() {
//
}

assert(Options(contentType: contentTypeJson).compose(bo1, '').contentType ==
contentTypeJson);

assert(Options(contentType: contentTypeJson).compose(bo2, '').contentType ==
contentTypeJson);

assert(Options(headers: jsonHeaders).compose(bo1, '').contentType ==
contentTypeJson);

assert(Options(headers: jsonHeaders).compose(bo2, '').contentType ==
contentTypeJson);
expect(
Options(contentType: contentTypeJson).compose(bo1, '').contentType,
contentTypeJson,
);
expect(
Options(contentType: contentTypeJson).compose(bo2, '').contentType,
contentTypeJson,
);
expect(
Options(contentType: contentTypeJson).compose(bo3, '').contentType,
contentTypeJson,
);
expect(
Options(headers: jsonHeaders).compose(bo1, '').contentType,
contentTypeJson,
);
expect(
Options(headers: jsonHeaders).compose(bo2, '').contentType,
contentTypeJson,
);
expect(
Options(headers: jsonHeaders).compose(bo3, '').contentType,
contentTypeJson,
);

/// RequestOptions
try {
Expand Down Expand Up @@ -226,9 +239,9 @@ void main() {

final r3 = await dio.get(
'',
options: Options(headers: {
Headers.contentTypeHeader: Headers.jsonContentType,
}),
options: Options(
headers: {Headers.contentTypeHeader: Headers.jsonContentType},
),
);
expect(
r3.requestOptions.headers[Headers.contentTypeHeader],
Expand All @@ -238,12 +251,13 @@ void main() {
final r4 = await dio.post('', data: '');
expect(
r4.requestOptions.headers[Headers.contentTypeHeader],
null,
Headers.jsonContentType,
);
});

test('#test default content-type 2', () async {
final dio = Dio();
dio.options.setRequestContentTypeWhenNoPayload = true;
dio.options.baseUrl = 'https://www.example.com';

final r1 = Options(method: 'GET').compose(dio.options, '/test').copyWith(
Expand All @@ -267,6 +281,7 @@ void main() {
);
assert(false);
} catch (_) {}
dio.options.setRequestContentTypeWhenNoPayload = false;

final r3 = Options(method: 'GET').compose(dio.options, '/test');
assert(r3.uri.toString() == 'https://www.example.com/test');
Expand Down
1 change: 0 additions & 1 deletion dio/test/request_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ void main() {
dio = Dio();
dio.options
..baseUrl = serverUrl.toString()
..contentType = Headers.jsonContentType
..connectTimeout = Duration(seconds: 1)
..receiveTimeout = Duration(seconds: 5)
..headers = {'User-Agent': 'dartisan'};
Expand Down

0 comments on commit 2e63df2

Please sign in to comment.