pub package package publisher

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 (mobile, desktop, and browser) and supports multiple implementations.

Using

The easiest way to use this library is via the top-level functions. They allow you to make individual HTTP requests with minimal hassle:

import 'package:http/http.dart' as http;

var url = Uri.https('example.com', 'whatsit/create');
var response = await http.post(url, body: {'name': 'doodle', 'color': 'blue'});
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');

print(await http.read(Uri.https('example.com', 'foobar.txt')));

Note

Flutter applications may require additional configuration 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:

var client = http.Client();
try {
  var response = await client.post(
      Uri.https('example.com', 'whatsit/create'),
      body: {'name': 'doodle', 'color': 'blue'});
  var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
  var uri = Uri.parse(decodedResponse['uri'] as String);
  print(await client.get(uri));
} finally {
  client.close();
}

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.

This package is designed to be composable. This makes it easy for external libraries to work with one another to add behavior to it. Libraries wishing to add behavior should create a subclass of BaseClient that wraps another Client and adds the desired behavior:

class UserAgentClient extends http.BaseClient {
  final String userAgent;
  final http.Client _inner;

  UserAgentClient(this.userAgent, this._inner);

  Future<http.StreamedResponse> send(http.BaseRequest request) {
    request.headers['user-agent'] = userAgent;
    return _inner.send(request);
  }
}

Retrying requests

package:http/retry.dart provides a class RetryClient to wrap an underlying http.Client which transparently retries failing requests.

import 'package:http/http.dart' as http;
import 'package:http/retry.dart';

Future<void> main() async {
  final client = RetryClient(http.Client());
  try {
    print(await client.read(Uri.http('example.org', '')));
  } finally {
    client.close();
  }
}

By default, this retries any request whose response has status code 503 Temporary Failure up to three retries. It waits 500ms before the first retry, and increases the delay by 1.5x each time. All of this can be customized using the RetryClient() constructor.

Choosing an implementation

There are multiple implementations of the package:http Client interface. By default, package:http uses BrowserClient on the web and IOClient on all other platforms. You an choose a different 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:

Implementation Supported Platforms SDK Caching HTTP3/QUIC Platform Native
package:httpIOClient Android, iOS, Linux, macOS, Windows Dart, Flutter
package:httpBrowserClient Web Dart, Flutter ✅︎ ✅︎
package:cupertino_httpCupertinoClient iOS, macOS Flutter ✅︎ ✅︎ ✅︎
package:cronet_httpCronetClient Android Flutter ✅︎ ✅︎
package:fetch_clientFetchClient Web Dart, Flutter ✅︎ ✅︎ ✅︎

Tip

If you are writing a Dart package or Flutter pluggin that uses package:http, you should not depend on a particular Client implementation. Let the application author decide what implementation is best for their project. You can make that easier by accepting an explicit Client argument. For example:

Future<Album> 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 the HTTP client 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:

# 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:

# Replace  "cupertino_http" with the package that you want to use.
flutter pub add cupertino_http

2. Configure the HTTP client.

Different package:http Client implementations may require different configuration options.

Add a function that returns a correctly configured Client. You can return a different Client on different platforms.

For example:

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 IOClient();
}

Tip

The Flutter HTTP example application demonstrates configuration best practices.

Supporting browser and native

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:

// -- http_client_factory.dart
Client httpClient() {
  if (Platform.isAndroid) {
    return CronetClient.defaultCronetEngine();
  }
  if (Platform.isIOS || Platform.isMacOS) {
    return CupertinoClient.defaultSessionConfiguration();
  }
  return IOClient();
}
// -- http_client_factory_web.dart
Client httpClient() => FetchClient();
// -- 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 to the places that use it is explicitly through arguments.

For example:

void main() {
  final client = httpClient();
  fetchAlbum(client, ...);
}

In Flutter, you can use a one of many state mangement approaches.

If you depend on code that uses top-level functions (e.g. http.post) or calls the Client() constructor, then you can use runWithClient to ensure that the correct Client is used. When an Isolate is spawned, it does not inherit any variables from the calling Zone, so runWithClient needs to be used in each Isolate that uses package:http.

You can ensure that only the Client that you have explicitly configured is used by defining no_default_http_client=true in the environment. This will also allow the default Client implementation to be removed, resulting in a reduced application size.

$ flutter build appbundle --dart-define=no_default_http_client=true ...
$ dart compile exe --define=no_default_http_client=true ...

Tip

The Flutter HTTP example application demonstrates how to make the configured Client available using package:provider and package:http_image_provider.

Libraries

browser_client
http
A composable, Future-based library for making HTTP requests.
io_client
retry
testing
This library contains testing classes for the HTTP library.