From ab3cc411168fc239cbd9e8055ed52dfa5f2ca3dc Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Wed, 1 Nov 2023 10:50:05 -0700 Subject: [PATCH 1/7] First run --- pkgs/http/README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index c889f2b54a..d3b627a3b4 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -100,3 +100,50 @@ and increases the delay by 1.5x each time. All of this can be customized using the [`RetryClient()`][new RetryClient] constructor. [new RetryClient]: https://pub.dev/documentation/http/latest/retry/RetryClient/RetryClient.html + +## Chosing an implementation + +There are multiple implementations of the `package:http` `Client` interface. +You can chose which implementation to use based on the needs of your +application. You can change implementations without changing your application +code, except for a few lines of [configuration](). + +Some well supported implementations are: + +| Implementation | Supported Platforms | Supports Caching | Supports HTTP3/QUIC | Platform Native | +| -------------- | ------------------- | ---------------- | ------------------- | --------------- | +| `package:http` — [`IOClient`][ioclient] | Android, iOS, Linux, macOS, Windows | ❌ | ❌ | ❌ | +| `package:http` — [`BrowserClient`][browserclient] | Web | ― | ✅︎ | ✅︎ | +| [`package:cupertino_http`][cupertinohttp] — [`CupertinoClient`][cupertinoclient] | iOS, macOS | ✅︎ | ✅︎ | ✅︎ | +| [`package:cronet_http`][cronethttp] — [`CronetClient`][cronetclient] | Android | ✅︎ | ✅︎ | ― | +| [`package:fetch_client`][fetch] — [`FetchClient`][fetchclient] | Web | ✅︎ | ✅︎ | ✅︎ | + + +[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html +[browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html +[cupertinohttp]: https://pub.dev/packages/cupertino_http +[cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html +[cronethttp]: https://pub.dev/packages/cronet_http +[cronetclient]: https://pub.dev/documentation/cronet_http/latest/cronet_http/CronetClient-class.html +[fetch]: https://pub.dev/packages/fetch_client +[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html + +## Configuration + +```terminal +flutter pub add http +``` + + +``` +late Client client; +if (Platform.isIOS) { + final config = URLSessionConfiguration.ephemeralSessionConfiguration() + ..allowsCellularAccess = false + ..allowsConstrainedNetworkAccess = false + ..allowsExpensiveNetworkAccess = false; + client = CupertinoClient.fromSessionConfiguration(config); +} else { + client = IOClient(); // Uses an HTTP client based on dart:io +} +``` \ No newline at end of file From f42543556067e5f34757f05c5022beb836a3e854 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 30 Nov 2023 12:43:23 -0800 Subject: [PATCH 2/7] tip --- pkgs/http/README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index d3b627a3b4..d655f98f5e 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -9,6 +9,11 @@ and the browser. ## Using +> [!TIP] +> The Dart [Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data) and Flutter +> [Networking Cookbook](https://docs.flutter.dev/data-and-backend/networking) have more detailed +> examples. + The easiest way to use this library is via the top-level functions. They allow you to make individual HTTP requests with minimal hassle: @@ -101,7 +106,7 @@ the [`RetryClient()`][new RetryClient] constructor. [new RetryClient]: https://pub.dev/documentation/http/latest/retry/RetryClient/RetryClient.html -## Chosing an implementation +## Choosing an implementation There are multiple implementations of the `package:http` `Client` interface. You can chose which implementation to use based on the needs of your @@ -110,13 +115,13 @@ code, except for a few lines of [configuration](). Some well supported implementations are: -| Implementation | Supported Platforms | Supports Caching | Supports HTTP3/QUIC | Platform Native | -| -------------- | ------------------- | ---------------- | ------------------- | --------------- | -| `package:http` — [`IOClient`][ioclient] | Android, iOS, Linux, macOS, Windows | ❌ | ❌ | ❌ | -| `package:http` — [`BrowserClient`][browserclient] | Web | ― | ✅︎ | ✅︎ | -| [`package:cupertino_http`][cupertinohttp] — [`CupertinoClient`][cupertinoclient] | iOS, macOS | ✅︎ | ✅︎ | ✅︎ | -| [`package:cronet_http`][cronethttp] — [`CronetClient`][cronetclient] | Android | ✅︎ | ✅︎ | ― | -| [`package:fetch_client`][fetch] — [`FetchClient`][fetchclient] | Web | ✅︎ | ✅︎ | ✅︎ | +| Implementation | Supported Platforms | SDK | Caching | HTTP3/QUIC | Platform Native | +| -------------- | ------------------- | ----| ------- | ---------- | --------------- | +| `package:http` — [`IOClient`][ioclient] | Android, iOS, Linux, macOS, Windows | Dart, Flutter | ❌ | ❌ | ❌ | +| `package:http` — [`BrowserClient`][browserclient] | Web | Flutter | ― | ✅︎ | ✅︎ | Dart, Flutter | +| [`package:cupertino_http`][cupertinohttp] — [`CupertinoClient`][cupertinoclient] | iOS, macOS | Flutter | ✅︎ | ✅︎ | ✅︎ | +| [`package:cronet_http`][cronethttp] — [`CronetClient`][cronetclient] | Android | Flutter | ✅︎ | ✅︎ | ― | +| [`package:fetch_client`][fetch] — [`FetchClient`][fetchclient] | Web | Dart, Flutter | ✅︎ | ✅︎ | ✅︎ | [ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html From 58f87c32c4ddcab934233869cf2369a849785929 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Fri, 1 Dec 2023 11:13:52 -0800 Subject: [PATCH 3/7] Update README.md --- pkgs/http/README.md | 128 +++++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 31 deletions(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index d655f98f5e..152e8965d0 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -4,16 +4,11 @@ A composable, Future-based library for making HTTP requests. This package contains a set of high-level functions and classes that make it -easy to consume HTTP resources. It's multi-platform, and supports mobile, desktop, -and the browser. +easy to consume HTTP resources. It's multi-platform (mobile, desktop, and +browser) and supports multiple implementations. ## Using -> [!TIP] -> The Dart [Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data) and Flutter -> [Networking Cookbook](https://docs.flutter.dev/data-and-backend/networking) have more detailed -> examples. - The easiest way to use this library is via the top-level functions. They allow you to make individual HTTP requests with minimal hassle: @@ -28,6 +23,11 @@ print('Response body: ${response.body}'); print(await http.read(Uri.https('example.com', 'foobar.txt'))); ``` +> [!NOTE] +> Flutter applications may require +> [additional configuration](https://docs.flutter.dev/data-and-backend/networking#platform-notes) +> to make HTTP requests. + If you're making multiple requests to the same server, you can keep open a persistent connection by using a [Client][] rather than making one-off requests. If you do this, make sure to close the client when you're done: @@ -46,6 +46,11 @@ try { } ``` +> [!TIP] +> For detailed background information and practical usage examples, see: +> - [Dart Development: Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data) +> - [Flutter Cookbook: Fetch data from the internet](https://docs.flutter.dev/cookbook/networking/fetch-data) + You can also exert more fine-grained control over your requests and responses by creating [Request][] or [StreamedRequest][] objects yourself and passing them to [Client.send][]. @@ -108,10 +113,10 @@ the [`RetryClient()`][new RetryClient] constructor. ## Choosing an implementation -There are multiple implementations of the `package:http` `Client` interface. -You can chose which implementation to use based on the needs of your -application. You can change implementations without changing your application -code, except for a few lines of [configuration](). +There are multiple implementations of the `package:http` [`Client`][client] interface. By default, `package:http` uses [`BrowserClient`][browserclient] on the web and [`IOClient`][ioclient] on all other platforms. You an choose a different [`Client`][client] implementation based on the needs of your application. + +You can change implementations without changing your application code, except +for a few lines of [configuration](). Some well supported implementations are: @@ -123,32 +128,93 @@ Some well supported implementations are: | [`package:cronet_http`][cronethttp] — [`CronetClient`][cronetclient] | Android | Flutter | ✅︎ | ✅︎ | ― | | [`package:fetch_client`][fetch] — [`FetchClient`][fetchclient] | Web | Dart, Flutter | ✅︎ | ✅︎ | ✅︎ | - -[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html -[browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html -[cupertinohttp]: https://pub.dev/packages/cupertino_http -[cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html -[cronethttp]: https://pub.dev/packages/cronet_http -[cronetclient]: https://pub.dev/documentation/cronet_http/latest/cronet_http/CronetClient-class.html -[fetch]: https://pub.dev/packages/fetch_client -[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html +> [!TIP] +> If you are writing a Dart package or Flutter pluggin that uses +> `package:http`, you should not depend on a particular [`Client`][client] +> implementation. Let the application author decide what implementation is +> best for their project. You can make that easier by accepting an explicit +> [`Client`][client] argument. For example: +> +> ```dart +> Future fetchAlbum({Client? client}) async { +> client ??= Client(); +> ... +> } +> ``` ## Configuration +To use a HTTP client implementation other than the default, you must: +1. Add the HTTP client as a dependency. +2. Configure the HTTP client. +3. Connect it to the code that uses it. + +### 1. Add the HTTP client as a dependency. + +To add a package compatible with the Dart SDK to your project, use `dart pub add`. + +For example: + ```terminal -flutter pub add http +# Replace "fetch_client" with the package that you want to use. +dart pub add fetch_client ``` +To add a package that requires the Flutter SDK, use `flutter pub add`. +For example: + +```terminal +# Replace "cupertino_http" with the package that you want to use. +flutter pub add cupertino_http ``` -late Client client; -if (Platform.isIOS) { - final config = URLSessionConfiguration.ephemeralSessionConfiguration() - ..allowsCellularAccess = false - ..allowsConstrainedNetworkAccess = false - ..allowsExpensiveNetworkAccess = false; - client = CupertinoClient.fromSessionConfiguration(config); -} else { - client = IOClient(); // Uses an HTTP client based on dart:io + +### 2. Configure the HTTP client. + +Different `package:http` [`Client`][client] implementations may require +different configuration options. + +Add a function that returns a correctly configured [`Client`][client]. You can +return a different [`Client`][client] on different platforms. + +For example: + +```dart +Client httpClient() { + if (Platform.isIOS || Platform.isMacOS) { + final config = URLSessionConfiguration.ephemeralSessionConfiguration() + ..cache = URLCache.withCapacity(memoryCapacity: 1000000); + return CupertinoClient.fromSessionConfiguration(config); + } + return Client(); // Return the default client for all other platforms. } -``` \ No newline at end of file +``` + + + +`runWithClient` +import 'package:provider/provider.dart'; + + + +https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example + + +For example: + +```terminal +flutter pub add cupertino_http +``` + +https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example + + +[client]: https://pub.dev/documentation/http/latest/http/Client-class.html +[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html +[browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html +[cupertinohttp]: https://pub.dev/packages/cupertino_http +[cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html +[cronethttp]: https://pub.dev/packages/cronet_http +[cronetclient]: https://pub.dev/documentation/cronet_http/latest/cronet_http/CronetClient-class.html +[fetch]: https://pub.dev/packages/fetch_client +[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html \ No newline at end of file From 15df7284f7fd1f1b79f3b922fc0085e5bd53c562 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 10:46:54 -0800 Subject: [PATCH 4/7] Update README.md --- pkgs/http/README.md | 80 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index 152e8965d0..e8ef130e47 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -50,6 +50,7 @@ try { > For detailed background information and practical usage examples, see: > - [Dart Development: Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data) > - [Flutter Cookbook: Fetch data from the internet](https://docs.flutter.dev/cookbook/networking/fetch-data) +> - [Flutter `package:http` example][flutterhttpexample] You can also exert more fine-grained control over your requests and responses by creating [Request][] or [StreamedRequest][] objects yourself and passing them to @@ -116,7 +117,7 @@ the [`RetryClient()`][new RetryClient] constructor. There are multiple implementations of the `package:http` [`Client`][client] interface. By default, `package:http` uses [`BrowserClient`][browserclient] on the web and [`IOClient`][ioclient] on all other platforms. You an choose a different [`Client`][client] implementation based on the needs of your application. You can change implementations without changing your application code, except -for a few lines of [configuration](). +for a few lines of [configuration](#2-configure-the-http-client). Some well supported implementations are: @@ -147,7 +148,7 @@ Some well supported implementations are: To use a HTTP client implementation other than the default, you must: 1. Add the HTTP client as a dependency. 2. Configure the HTTP client. -3. Connect it to the code that uses it. +3. Connect the HTTP client to the code that uses it. ### 1. Add the HTTP client as a dependency. @@ -181,40 +182,95 @@ For example: ```dart Client httpClient() { + if (Platform.isAndroid) { + final engine = CronetEngine.build( + cacheMode: CacheMode.memory, + cacheMaxSize: 1000000); + return CronetClient.fromCronetEngine(engine); + } if (Platform.isIOS || Platform.isMacOS) { final config = URLSessionConfiguration.ephemeralSessionConfiguration() ..cache = URLCache.withCapacity(memoryCapacity: 1000000); return CupertinoClient.fromSessionConfiguration(config); } - return Client(); // Return the default client for all other platforms. + return IOClient(); } ``` +> [!TIP] +> [The Flutter HTTP example application][flutterhttpexample] demonstrates +> configuration best practices. +#### Supporting browser and native -`runWithClient` -import 'package:provider/provider.dart'; +If your application can be run in the browser and natively, you must put your +browser and native configurations in seperate files and import the correct file +based on the platform. +For example: +```dart +// -- http_client_factory.dart +Client httpClient() { + if (Platform.isAndroid) { + return CronetClient.defaultCronetEngine(); + } + if (Platform.isIOS || Platform.isMacOS) { + return CupertinoClient.defaultSessionConfiguration(); + } + return IOClient(); +} +``` -https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example +```dart +// -- http_client_factory_web.dart +Client httpClient() => FetchClient(); +``` +```dart +// -- main.dart +import 'http_client_factory.dart' + if (dart.library.js_interop) 'http_client_factory_web.dart' + +// The correct `httpClient` will be available. +``` + +### 3. Connect the HTTP client to the code that uses it. + +The best way to pass [`Client`s][client] to the places that use them is +explicitly through arguments. For example: -```terminal -flutter pub add cupertino_http +```dart +void main() { + Client client = httpClient(); + fetchAlbum(client, ...); +} ``` -https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example +In Flutter, you can use [`package:provider`][provider] to make the correct +[`Client`][client] availble to `State` objects. +If you depend on code that uses top-level functions (e.g. `http.post`) or +calls the [`Client()`] constructor, then you can use +[`runWithClient`](runwithclient) to ensure that the correct +[`Client`][client] is used. + +> [!TIP] +> [The Flutter HTTP example application][flutterhttpexample] demonstrates +> how to make the configured [`Client`][client] available using +> [`package:provider`][provider] and [`runWithClient`](runwithclient). -[client]: https://pub.dev/documentation/http/latest/http/Client-class.html -[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html [browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html +[client]: https://pub.dev/documentation/http/latest/http/Client-class.html [cupertinohttp]: https://pub.dev/packages/cupertino_http [cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html [cronethttp]: https://pub.dev/packages/cronet_http [cronetclient]: https://pub.dev/documentation/cronet_http/latest/cronet_http/CronetClient-class.html [fetch]: https://pub.dev/packages/fetch_client -[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html \ No newline at end of file +[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html +[flutterhttpexample]: https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example +[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html +[provider]: https://pub.dev/packages/provider +[runwithclient]: https://pub.dev/documentation/http/latest/http/runWithClient.html From a5679cf28431d464e57a6dcedc083914ad6ed68d Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 10:54:46 -0800 Subject: [PATCH 5/7] Update links --- pkgs/http/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index e8ef130e47..0a06e279d7 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -50,7 +50,7 @@ try { > For detailed background information and practical usage examples, see: > - [Dart Development: Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data) > - [Flutter Cookbook: Fetch data from the internet](https://docs.flutter.dev/cookbook/networking/fetch-data) -> - [Flutter `package:http` example][flutterhttpexample] +> - [The Flutter HTTP example application][flutterhttpexample] You can also exert more fine-grained control over your requests and responses by creating [Request][] or [StreamedRequest][] objects yourself and passing them to @@ -237,7 +237,7 @@ import 'http_client_factory.dart' ### 3. Connect the HTTP client to the code that uses it. -The best way to pass [`Client`s][client] to the places that use them is +The best way to pass [`Client`][client] to the places that use it is explicitly through arguments. For example: @@ -253,7 +253,7 @@ In Flutter, you can use [`package:provider`][provider] to make the correct [`Client`][client] availble to `State` objects. If you depend on code that uses top-level functions (e.g. `http.post`) or -calls the [`Client()`] constructor, then you can use +calls the [`Client()`][clientconstructor] constructor, then you can use [`runWithClient`](runwithclient) to ensure that the correct [`Client`][client] is used. @@ -264,6 +264,7 @@ calls the [`Client()`] constructor, then you can use [browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html [client]: https://pub.dev/documentation/http/latest/http/Client-class.html +[clientconstructor]: https://pub.dev/documentation/http/latest/http/Client/Client.html [cupertinohttp]: https://pub.dev/packages/cupertino_http [cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html [cronethttp]: https://pub.dev/packages/cronet_http From e2620ee6fc6fabca6232de5f933d28421dc98a4b Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:29:56 -0800 Subject: [PATCH 6/7] Update pkgs/http/README.md Co-authored-by: Nate Bosch --- pkgs/http/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index 0a06e279d7..afa1c89a7d 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -244,7 +244,7 @@ For example: ```dart void main() { - Client client = httpClient(); + var client = httpClient(); fetchAlbum(client, ...); } ``` From f1a899ee466b421c6a362d406609c8a3e0455e79 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:35:38 -0800 Subject: [PATCH 7/7] Update README.md --- pkgs/http/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkgs/http/README.md b/pkgs/http/README.md index afa1c89a7d..689e8fbe4e 100644 --- a/pkgs/http/README.md +++ b/pkgs/http/README.md @@ -244,13 +244,13 @@ For example: ```dart void main() { - var client = httpClient(); + final client = httpClient(); fetchAlbum(client, ...); } ``` -In Flutter, you can use [`package:provider`][provider] to make the correct -[`Client`][client] availble to `State` objects. +In Flutter, you can use a one of many +[state mangement approaches][flutterstatemanagement]. If you depend on code that uses top-level functions (e.g. `http.post`) or calls the [`Client()`][clientconstructor] constructor, then you can use @@ -273,5 +273,6 @@ calls the [`Client()`][clientconstructor] constructor, then you can use [fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html [flutterhttpexample]: https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example [ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html +[flutterstatemanagement]: https://docs.flutter.dev/data-and-backend/state-mgmt/options [provider]: https://pub.dev/packages/provider [runwithclient]: https://pub.dev/documentation/http/latest/http/runWithClient.html