clue/buzz-react

Simple async HTTP client for fetching URLs, talking to RESTful APIs, downloading, following redirects etc.

Installs: 1 738

Dependents: 5

Stars: 19

Watchers: 2

Forks: 7

Open Issues: 12

Language: PHP

v0.3.0 2015-06-14 10:50 UTC

README

Simple async HTTP client for concurrently interacting with multiple HTTP servers, fetching URLs, talking to RESTful APIs, downloading files, following redirects etc. all at the same time.

This library is heavily inspired by the great kriswallsmith/Buzz project. However, instead of blocking on each request, it relies on React PHP's EventLoop to process multiple requests in parallel.

React PHP also provides the package react/http-client which provides a streaming HTTP client implementation. That package is ideally suited for accessing streaming APIs or processing huge requests, but requires quite a bit of boilerplate code if all you want to do is to access a normal website or your average RESTful API.

As such, this projects aims at providing a higher level API that is easy to use in order to process multiple HTTP requests concurrently without having to mess with most of the low level details of the underlying react/http-client.

Note: This project is in beta stage! Feel free to report any issues you encounter.

Quickstart example

Once installed, you can use the following code to access a HTTP webserver and send some simple HTTP GET requests:

$loop = React\EventLoop\Factory::create();
$client = new Browser($loop);

$client->get('http://www.google.com/')->then(function (Response $result) {
    var_dump($result->getHeaders(), $result->getBody());
});

$loop->run();

See also the examples.

Usage

Browser

The Browser is responsible for sending HTTP requests to your HTTP server and keeps track of pending incoming HTTP responses. It also registers everything with the main EventLoop.

$loop = React\EventLoop\Factory::create();
$browser = new Browser($loop);

If you need custom DNS or proxy settings, you can explicitly pass a custom Sender instance. This is considered advanced usage.

Methods

The Browser offers several methods that resemble the HTTP protocol methods:

$browser->get($url, array $headers = array());
$browser->head($url, array $headers = array());
$browser->post($url, array $headers = array(), $content = '');
$browser->delete($url, array $headers = array(), $content = '');
$browser->put($url, array $headers = array(), $content = '');
$browser->patch($url, array $headers = array(), $content = '');

If you need a custom HTTP protocol method, you can use the send() method.

Processing

Sending requests is async (non-blocking), so you can actually send multiple requests in parallel. The Browser will respond to each request with a Response message, the order is not guaranteed. Sending requests uses a Promise-based interface that makes it easy to react to when a transaction is fulfilled (i.e. either successfully resolved or rejected with an error):

$browser->get($url)->then(
    function ($response) {
        var_dump('Response received', $response);
    },
    function (Exception $error) {
        var_dump('There was an error', $error->getMessage());
    }
});
submit()

The submit($url, array $fields, $headers = array(), $method = 'POST') method can be used to submit an array of field values similar to submitting a form (application/x-www-form-urlencoded).

send()

The send(Request $request) method can be used to send an arbitrary Request object.

withOptions()

The withOptions(array $options) method can be used to change the options to use:

$newBrowser = $browser->withOptions($options);

Notice that the Browser is an immutable object, i.e. the withOptions() method actually returns a new Browser instance with the options applied.

See options for more details.

withSender()

The withSender(Sender $sender) method can be used to change the Sender instance to use:

$newBrowser = $browser->withSender($sender);

Notice that the Browser is an immutable object, i.e. the withSender() method actually returns a new Browser instance with the given Sender applied.

See Sender for more details.

Message

The Message is an abstract base class for the Response and Request. It provides a common interface for these message types.

See its class outline for more details.

Response

The Response value object represents the incoming response received from the Browser. It shares all properties of the Message parent class.

See its class outline for more details.

Request

The Request value object represents the outgoing request to be sent via the Browser. It shares all properties of the Message parent class.

See its class outline for more details.

getUri()

The getUri() method can be used to get its Uri instance.

Uri

Each Request contains a (full) absolute request URI.

$request = new Request('GET', 'http://www.google.com/');
$uri = $request->getUri();

assert('http' == $uri->getScheme());
assert('www.google.com' == $uri->getHost());
assert('/' == $uri->getPath());

See its class outline for more details.

ResponseException

The ResponseException is an Exception sub-class that will be used to reject a request promise if the remote server returns a non-success status code (anything but 2xx or 3xx). You can control this behavior via the "obeySuccessCode" option.

The getCode() method can be used to return the HTTP response status code.

The getResponse() method can be used to access its underlying Response object.

Advanced

Sender

The Sender is responsible for passing the Request objects to the underlying HttpClient library and keeps track of its transmission and converts its reponses back to Response objects.

It also registers everything with the main EventLoop and the default Connector and DNS Resolver.

See also Browser::withSender() for changing the Sender instance during runtime.

DNS

The Sender is also resposible for creating the underlying TCP/IP connection to the remove HTTP server and hence has to orchestrate DNS lookups. By default, it uses a Connector instance which uses Google's public DNS servers (8.8.8.8).

If you need custom DNS settings, you explicitly create a Sender instance with your DNS server address (or React\Dns\Resolver instance) like this:

$dns = '127.0.0.1';
$sender = Sender::createFromLoopDns($loop, $dns);
$browser = $browser->withSender($sender);

See also Browser::withSender() for more details.

SOCKS proxy

You can also establish your outgoing connections through a SOCKS proxy server by adding a dependency to clue/socks-react.

The SOCKS protocol operates at the TCP/IP layer and thus requires minimal effort at the HTTP application layer. This works for both plain HTTP and SSL encrypted HTTPS requests.

See also the SOCKS example.

UNIX domain sockets

This library also supports connecting to a local UNIX domain socket path. You have to explicitly create a Sender that passes every request through the given UNIX domain socket. For consistency reasons you still have to pass full HTTP URLs for every request, but the host and port will be ignored when establishing a connection.

$path = 'unix:///tmp/daemon.sock';
$sender = Sender::createFromLoopUnix($loop, $path);
$client = new Browser($loop, $sender);

$client->get('http://localhost/demo');

Options

Note: This API is subject to change.

The Browser class exposes several options for the handling of HTTP transactions. These options resemble some of PHP's HTTP context options and can be controlled via the following API (and their defaults):

$newBrowser = $browser->withOptions(array(
    'followRedirects' => true,
    'maxRedirects' => 10,
    'obeySuccessCode' => true
));

Notice that the Browser is an immutable object, i.e. the withOptions() method actually returns a new Browser instance with the options applied.

Streaming

Note: This API is subject to change.

The Sender emits a progress event array on its Promise that can be used to intercept the underlying outgoing request stream (React\HttpClient\Request in the requestStream key) and the incoming response stream (React\HttpClient\Response in the responseStream key).

$client->get('http://www.google.com/')->then($handler, null, function ($event) {
    if (isset($event['responseStream'])) {
        /* @var $stream React\HttpClient\Response */
        $stream = $event['responseStream'];
        $stream->on('data', function ($data) { });
    }
});

Install

The recommended way to install this library is through composer. New to composer?

{
    "require": {
        "clue/buzz-react": "~0.3.0"
    }
}

License

MIT