Skip to content

Commit c90496e

Browse files
authored
Document how to use replacement Client implementations (#1063)
1 parent c8536e4 commit c90496e

File tree

1 file changed

+178
-2
lines changed

1 file changed

+178
-2
lines changed

pkgs/http/README.md

Lines changed: 178 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
A composable, Future-based library for making HTTP requests.
55

66
This package contains a set of high-level functions and classes that make it
7-
easy to consume HTTP resources. It's multi-platform, and supports mobile, desktop,
8-
and the browser.
7+
easy to consume HTTP resources. It's multi-platform (mobile, desktop, and
8+
browser) and supports multiple implementations.
99

1010
## Using
1111

@@ -23,6 +23,11 @@ print('Response body: ${response.body}');
2323
print(await http.read(Uri.https('example.com', 'foobar.txt')));
2424
```
2525

26+
> [!NOTE]
27+
> Flutter applications may require
28+
> [additional configuration](https://docs.flutter.dev/data-and-backend/networking#platform-notes)
29+
> to make HTTP requests.
30+
2631
If you're making multiple requests to the same server, you can keep open a
2732
persistent connection by using a [Client][] rather than making one-off requests.
2833
If you do this, make sure to close the client when you're done:
@@ -41,6 +46,12 @@ try {
4146
}
4247
```
4348

49+
> [!TIP]
50+
> For detailed background information and practical usage examples, see:
51+
> - [Dart Development: Fetch data from the internet](https://dart.dev/tutorials/server/fetch-data)
52+
> - [Flutter Cookbook: Fetch data from the internet](https://docs.flutter.dev/cookbook/networking/fetch-data)
53+
> - [The Flutter HTTP example application][flutterhttpexample]
54+
4455
You can also exert more fine-grained control over your requests and responses by
4556
creating [Request][] or [StreamedRequest][] objects yourself and passing them to
4657
[Client.send][].
@@ -100,3 +111,168 @@ and increases the delay by 1.5x each time. All of this can be customized using
100111
the [`RetryClient()`][new RetryClient] constructor.
101112

102113
[new RetryClient]: https://pub.dev/documentation/http/latest/retry/RetryClient/RetryClient.html
114+
115+
## Choosing an implementation
116+
117+
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.
118+
119+
You can change implementations without changing your application code, except
120+
for a few lines of [configuration](#2-configure-the-http-client).
121+
122+
Some well supported implementations are:
123+
124+
| Implementation | Supported Platforms | SDK | Caching | HTTP3/QUIC | Platform Native |
125+
| -------------- | ------------------- | ----| ------- | ---------- | --------------- |
126+
| `package:http`[`IOClient`][ioclient] | Android, iOS, Linux, macOS, Windows | Dart, Flutter ||||
127+
| `package:http`[`BrowserClient`][browserclient] | Web | Flutter || ✅︎ | ✅︎ | Dart, Flutter |
128+
| [`package:cupertino_http`][cupertinohttp][`CupertinoClient`][cupertinoclient] | iOS, macOS | Flutter | ✅︎ | ✅︎ | ✅︎ |
129+
| [`package:cronet_http`][cronethttp][`CronetClient`][cronetclient] | Android | Flutter | ✅︎ | ✅︎ ||
130+
| [`package:fetch_client`][fetch][`FetchClient`][fetchclient] | Web | Dart, Flutter | ✅︎ | ✅︎ | ✅︎ |
131+
132+
> [!TIP]
133+
> If you are writing a Dart package or Flutter pluggin that uses
134+
> `package:http`, you should not depend on a particular [`Client`][client]
135+
> implementation. Let the application author decide what implementation is
136+
> best for their project. You can make that easier by accepting an explicit
137+
> [`Client`][client] argument. For example:
138+
>
139+
> ```dart
140+
> Future<Album> fetchAlbum({Client? client}) async {
141+
> client ??= Client();
142+
> ...
143+
> }
144+
> ```
145+
146+
## Configuration
147+
148+
To use a HTTP client implementation other than the default, you must:
149+
1. Add the HTTP client as a dependency.
150+
2. Configure the HTTP client.
151+
3. Connect the HTTP client to the code that uses it.
152+
153+
### 1. Add the HTTP client as a dependency.
154+
155+
To add a package compatible with the Dart SDK to your project, use `dart pub add`.
156+
157+
For example:
158+
159+
```terminal
160+
# Replace "fetch_client" with the package that you want to use.
161+
dart pub add fetch_client
162+
```
163+
164+
To add a package that requires the Flutter SDK, use `flutter pub add`.
165+
166+
For example:
167+
168+
```terminal
169+
# Replace "cupertino_http" with the package that you want to use.
170+
flutter pub add cupertino_http
171+
```
172+
173+
### 2. Configure the HTTP client.
174+
175+
Different `package:http` [`Client`][client] implementations may require
176+
different configuration options.
177+
178+
Add a function that returns a correctly configured [`Client`][client]. You can
179+
return a different [`Client`][client] on different platforms.
180+
181+
For example:
182+
183+
```dart
184+
Client httpClient() {
185+
if (Platform.isAndroid) {
186+
final engine = CronetEngine.build(
187+
cacheMode: CacheMode.memory,
188+
cacheMaxSize: 1000000);
189+
return CronetClient.fromCronetEngine(engine);
190+
}
191+
if (Platform.isIOS || Platform.isMacOS) {
192+
final config = URLSessionConfiguration.ephemeralSessionConfiguration()
193+
..cache = URLCache.withCapacity(memoryCapacity: 1000000);
194+
return CupertinoClient.fromSessionConfiguration(config);
195+
}
196+
return IOClient();
197+
}
198+
```
199+
200+
> [!TIP]
201+
> [The Flutter HTTP example application][flutterhttpexample] demonstrates
202+
> configuration best practices.
203+
204+
#### Supporting browser and native
205+
206+
If your application can be run in the browser and natively, you must put your
207+
browser and native configurations in seperate files and import the correct file
208+
based on the platform.
209+
210+
For example:
211+
212+
```dart
213+
// -- http_client_factory.dart
214+
Client httpClient() {
215+
if (Platform.isAndroid) {
216+
return CronetClient.defaultCronetEngine();
217+
}
218+
if (Platform.isIOS || Platform.isMacOS) {
219+
return CupertinoClient.defaultSessionConfiguration();
220+
}
221+
return IOClient();
222+
}
223+
```
224+
225+
```dart
226+
// -- http_client_factory_web.dart
227+
Client httpClient() => FetchClient();
228+
```
229+
230+
```dart
231+
// -- main.dart
232+
import 'http_client_factory.dart'
233+
if (dart.library.js_interop) 'http_client_factory_web.dart'
234+
235+
// The correct `httpClient` will be available.
236+
```
237+
238+
### 3. Connect the HTTP client to the code that uses it.
239+
240+
The best way to pass [`Client`][client] to the places that use it is
241+
explicitly through arguments.
242+
243+
For example:
244+
245+
```dart
246+
void main() {
247+
final client = httpClient();
248+
fetchAlbum(client, ...);
249+
}
250+
```
251+
252+
In Flutter, you can use a one of many
253+
[state mangement approaches][flutterstatemanagement].
254+
255+
If you depend on code that uses top-level functions (e.g. `http.post`) or
256+
calls the [`Client()`][clientconstructor] constructor, then you can use
257+
[`runWithClient`](runwithclient) to ensure that the correct
258+
[`Client`][client] is used.
259+
260+
> [!TIP]
261+
> [The Flutter HTTP example application][flutterhttpexample] demonstrates
262+
> how to make the configured [`Client`][client] available using
263+
> [`package:provider`][provider] and [`runWithClient`](runwithclient).
264+
265+
[browserclient]: https://pub.dev/documentation/http/latest/browser_client/BrowserClient-class.html
266+
[client]: https://pub.dev/documentation/http/latest/http/Client-class.html
267+
[clientconstructor]: https://pub.dev/documentation/http/latest/http/Client/Client.html
268+
[cupertinohttp]: https://pub.dev/packages/cupertino_http
269+
[cupertinoclient]: https://pub.dev/documentation/cupertino_http/latest/cupertino_http/CupertinoClient-class.html
270+
[cronethttp]: https://pub.dev/packages/cronet_http
271+
[cronetclient]: https://pub.dev/documentation/cronet_http/latest/cronet_http/CronetClient-class.html
272+
[fetch]: https://pub.dev/packages/fetch_client
273+
[fetchclient]: https://pub.dev/documentation/fetch_client/latest/fetch_client/FetchClient-class.html
274+
[flutterhttpexample]: https://github.com/dart-lang/http/tree/master/pkgs/flutter_http_example
275+
[ioclient]: https://pub.dev/documentation/http/latest/io_client/IOClient-class.html
276+
[flutterstatemanagement]: https://docs.flutter.dev/data-and-backend/state-mgmt/options
277+
[provider]: https://pub.dev/packages/provider
278+
[runwithclient]: https://pub.dev/documentation/http/latest/http/runWithClient.html

0 commit comments

Comments
 (0)