Use spawnHybrid for the stub server (#700)

Move the in-process stub server from `test/io/utils.dart` to
`test/stub_server.dart` as a `hybridMain`. This will allow spawning the
server from the browser tests as well.

The browser tests still do not work against this server. Separate out
the change in how the server is started from the (potential) other
changes with fixes.

Update tests to use the new pattern - they call `startServer` and wait
for the `serverUrl`. No explicit teardown is needed because the
`spawnHybrid` call gets an implicit `addTearDown` which kills the
isolate.

Remove `test/io/utils.dart` entirely. Inline the definition of
`throwsSocketException` at the single use site.
Make the `message` argument to the other copy of `throwsClientException`
optional and use it in place of the version that had been in
`test/io/utils.dart`.
9 files changed
tree: 79017a7ada3bb314ef630795884066b61abc5333
  1. .github/
  2. example/
  3. lib/
  4. test/
  5. .gitignore
  6. analysis_options.yaml
  7. CHANGELOG.md
  8. LICENSE
  9. pubspec.yaml
  10. README.md
README.md

A composable, Future-based library for making HTTP requests.

pub package Build Status

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.

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.parse('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.parse('https://example.com/foobar.txt')));

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.parse('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.