diff --git a/dio/CHANGELOG.md b/dio/CHANGELOG.md index 9ed27486d..0c275cbd5 100644 --- a/dio/CHANGELOG.md +++ b/dio/CHANGELOG.md @@ -5,7 +5,7 @@ See the [Migration Guide][] for the complete breaking changes list.** ## Unreleased -*None.* +- Raise warning for `Map`s other than `Map` when encoding request data. ## 5.3.3 diff --git a/dio/lib/src/adapters/browser_adapter.dart b/dio/lib/src/adapters/browser_adapter.dart index eab026f17..399113c76 100644 --- a/dio/lib/src/adapters/browser_adapter.dart +++ b/dio/lib/src/adapters/browser_adapter.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:html'; import 'dart:typed_data'; -import 'dart:developer' as dev; import 'package:meta/meta.dart'; @@ -10,13 +9,7 @@ import '../adapter.dart'; import '../dio_exception.dart'; import '../headers.dart'; import '../options.dart'; - -// For the web platform, an inline `bool.fromEnvironment` translates to -// `core.bool.fromEnvironment` instead of correctly being replaced by the -// constant value found in the environment at build time. -// -// See https://github.com/flutter/flutter/issues/51186. -const _kReleaseMode = bool.fromEnvironment('dart.vm.product'); +import '../utils.dart'; HttpClientAdapter createAdapter() => BrowserHttpClientAdapter(); @@ -161,21 +154,17 @@ class BrowserHttpClientAdapter implements HttpClientAdapter { } }); } - } else if (!_kReleaseMode) { + } else { if (options.sendTimeout != null) { - dev.log( + debugLog( 'sendTimeout cannot be used without a request body to send', - level: 900, - name: '🔔 Dio', - stackTrace: StackTrace.current, + StackTrace.current, ); } if (options.onSendProgress != null) { - dev.log( + debugLog( 'onSendProgress cannot be used without a request body to send', - level: 900, - name: '🔔 Dio', - stackTrace: StackTrace.current, + StackTrace.current, ); } } @@ -262,13 +251,11 @@ class BrowserHttpClientAdapter implements HttpClientAdapter { }); if (requestStream != null) { - if (!_kReleaseMode && options.method == 'GET') { - dev.log( + if (options.method == 'GET') { + debugLog( 'GET request with a body data are not support on the ' 'web platform. Use POST/PUT instead.', - level: 900, - name: '🔔 Dio', - stackTrace: StackTrace.current, + StackTrace.current, ); } final completer = Completer(); diff --git a/dio/lib/src/compute/compute_io.dart b/dio/lib/src/compute/compute_io.dart index 71b4d5158..f45646bfe 100644 --- a/dio/lib/src/compute/compute_io.dart +++ b/dio/lib/src/compute/compute_io.dart @@ -22,17 +22,16 @@ import 'dart:async'; import 'dart:developer'; import 'dart:isolate'; +import '../utils.dart' show kReleaseMode; import 'compute.dart' as c; -const _kReleaseMode = bool.fromEnvironment('dart.vm.product'); - /// The dart:io implementation of [c.compute]. Future compute( c.ComputeCallback callback, Q message, { String? debugLabel, }) async { - debugLabel ??= _kReleaseMode ? 'compute' : callback.toString(); + debugLabel ??= kReleaseMode ? 'compute' : callback.toString(); final Flow flow = Flow.begin(); Timeline.startSync('$debugLabel: start', flow: flow); diff --git a/dio/lib/src/interceptors/imply_content_type.dart b/dio/lib/src/interceptors/imply_content_type.dart index a26015abc..6664d323d 100644 --- a/dio/lib/src/interceptors/imply_content_type.dart +++ b/dio/lib/src/interceptors/imply_content_type.dart @@ -1,16 +1,8 @@ -import 'dart:developer' as dev; - import '../dio_mixin.dart'; import '../form_data.dart'; import '../headers.dart'; import '../options.dart'; - -// For the web platform, an inline `bool.fromEnvironment` translates to -// `core.bool.fromEnvironment` instead of correctly being replaced by the -// constant value found in the environment at build time. -// -// See https://github.com/flutter/flutter/issues/51186. -const _kReleaseMode = bool.fromEnvironment('dart.vm.product'); +import '../utils.dart'; /// {@template dio.interceptors.ImplyContentTypeInterceptor} /// The default `content-type` for requests will be implied by the @@ -34,17 +26,12 @@ class ImplyContentTypeInterceptor extends Interceptor { } else if (data is List || data is Map || data is String) { contentType = Headers.jsonContentType; } else { - // Do not log in the release mode. - if (!_kReleaseMode) { - dev.log( - '${data.runtimeType} cannot be used ' - 'to imply a default content-type, ' - 'please set a proper content-type in the request.', - level: 900, - name: '🔔 Dio', - stackTrace: StackTrace.current, - ); - } + debugLog( + '${data.runtimeType} cannot be used ' + 'to imply a default content-type, ' + 'please set a proper content-type in the request.', + StackTrace.current, + ); contentType = null; } options.contentType = contentType; diff --git a/dio/lib/src/transformers/sync_transformer.dart b/dio/lib/src/transformers/sync_transformer.dart index f2b666299..54da8ccfb 100644 --- a/dio/lib/src/transformers/sync_transformer.dart +++ b/dio/lib/src/transformers/sync_transformer.dart @@ -6,6 +6,7 @@ import '../adapter.dart'; import '../headers.dart'; import '../options.dart'; import '../transformer.dart'; +import '../utils.dart'; @Deprecated('Use BackgroundTransformer instead') typedef DefaultTransformer = SyncTransformer; @@ -30,11 +31,21 @@ class SyncTransformer extends Transformer { @override Future transformRequest(RequestOptions options) async { - final dynamic data = options.data ?? ''; + final Object data = options.data ?? ''; if (data is! String && Transformer.isJsonMimeType(options.contentType)) { return jsonEncodeCallback(data); - } else if (data is Map) { - return Transformer.urlEncodeMap(data, options.listFormat); + } else if (data is Map) { + if (data is Map) { + return Transformer.urlEncodeMap(data, options.listFormat); + } + debugLog( + 'The data is a type of `Map` (${data.runtimeType}), ' + 'but the transformer can only encode `Map`.\n' + 'If you are writing maps using `{}`, ' + 'consider writing `{}`.', + StackTrace.current, + ); + return data.toString(); } else { return data.toString(); } diff --git a/dio/lib/src/utils.dart b/dio/lib/src/utils.dart index 586b5384d..0073bd7b0 100644 --- a/dio/lib/src/utils.dart +++ b/dio/lib/src/utils.dart @@ -1,10 +1,18 @@ import 'dart:async'; import 'dart:collection'; import 'dart:convert'; +import 'dart:developer' as dev; import 'options.dart'; import 'parameter.dart'; +// For the web platform, an inline `bool.fromEnvironment` translates to +// `core.bool.fromEnvironment` instead of correctly being replaced by the +// constant value found in the environment at build time. +// +// See https://github.com/flutter/flutter/issues/51186. +const kReleaseMode = bool.fromEnvironment('dart.vm.product'); + /// Pipes all data and errors from [stream] into [sink]. Completes [Future] once /// [stream] is done. Unlike [store], [sink] remains open after [stream] is /// done. @@ -30,7 +38,7 @@ Encoding encodingForCharset(String? charset, [Encoding fallback = latin1]) { typedef DioEncodeHandler = String? Function(String key, Object? value); String encodeMap( - data, + Object data, DioEncodeHandler handler, { bool encode = true, bool isQuery = false, @@ -43,7 +51,9 @@ String encodeMap( // When [encode] is false, for example for [FormData], nothing is encoded. final leftBracket = isQuery || !encode ? '[' : '%5B'; final rightBracket = isQuery || !encode ? ']' : '%5D'; - final encodeComponent = encode ? Uri.encodeQueryComponent : (e) => e; + + final String Function(String) encodeComponent = + encode ? Uri.encodeQueryComponent : (e) => e; Object? maybeEncode(Object? value) { if (!isQuery || value == null || value is! String) { return value; @@ -85,7 +95,7 @@ String encodeMap( } else if (sub is Map) { sub.forEach((k, v) { if (path == '') { - urlEncode(maybeEncode(v), '${encodeComponent(k)}'); + urlEncode(maybeEncode(v), encodeComponent(k)); } else { urlEncode( maybeEncode(v), @@ -133,3 +143,15 @@ Map caseInsensitiveKeyMap([Map? value]) { if (value != null && value.isNotEmpty) map.addAll(value); return map; } + +// TODO(Alex): Provide a configurable property on the Dio class once https://github.com/cfug/dio/discussions/1982 has made some progress. +void debugLog(String message, StackTrace stackTrace) { + if (!kReleaseMode) { + dev.log( + message, + level: 900, + name: '🔔 Dio', + stackTrace: stackTrace, + ); + } +}