HTTPlug Tutorial

This tutorial should give you an idea how to use HTTPlug in your project. HTTPlug has two main use cases:

  1. Usage in your project;

  2. Usage in a reusable package.

This tutorial will start with the first use case and then explain the special considerations to take into account when building a reusable package.

We use Composer for dependency management. Install it if you don’t have it yet.

Note

If you are using a framework, check the Framework Integrations to see if there is an integration available. Framework integrations will simplify the way you set up clients, letting you focus on handling the requests.

Setting up the Project

mkdir httplug-tutorial
cd httplug-tutorial
composer init
# specify your information as you want. say no to defining the dependencies interactively
composer require php-http/guzzle6-adapter

The last command will install Guzzle as well as the Guzzle HTTPlug adapter and the required interface repositories. We are now ready to start coding.

Writing Some Simple Code

Create a file demo.php in the root folder and write the following code:

<?php
require('vendor/autoload.php');

use Http\Discovery\HttpClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;

$client = HttpClientDiscovery::find();
$messageFactory = MessageFactoryDiscovery::find();
$homeResponse = $client->sendRequest(
    $messageFactory->createRequest('GET', 'http://httplug.io')
);

var_dump($homeResponse->getStatusCode()); // 200, hopefully

$missingPageResponse = $client->sendRequest(
    $messageFactory->createRequest('GET', 'http://httplug.io/missingPage')
);

var_dump($missingPageResponse->getStatusCode()); // 404

Using an Asynchronous Client

Asynchronous client accepts a PSR-7 RequestInterface and returns a Http\Promise\Promise:

use Http\Discovery\HttpAsyncClientDiscovery;

$httpAsyncClient = HttpAsyncClientDiscovery::find();
$promise = $httpAsyncClient->sendAsyncRequest($request);

Using the Callback System

The promise allows you to add callbacks for when the response is available or an errors happens by using the then method:

$promise->then(function (ResponseInterface $response) {
    // onFulfilled callback
    echo 'The response is available';

    return $response;
}, function (Exception $e) {
    // onRejected callback
    echo 'An error happens';

    throw $e;
});

This method will return another promise so you can manipulate the response and/or exception and still provide a way to interact with this object for your users:

$promise->then(function (ResponseInterface $response) {
    // onFulfilled callback
    echo 'The response is available';

    return $response;
}, function (Exception $e) {
    // onRejected callback
    echo 'An error happens';

    throw $e;
})->then(function (ResponseInterface $response) {
    echo 'Response still available';

    return $response;
}, function (Exception $e) {
     throw $e
});

In order to achieve the chain callback, if you read previous examples carefully, callbacks provided to the then method must return a PSR-7 ResponseInterface or throw a Http\Client\Exception. For both of the callbacks, if it returns a PSR-7 ResponseInterface it will call the onFulfilled callback for the next element in the chain, if it throws a Http\Client\Exception it will call the onRejected callback.

i.e. you can inverse the behavior of a call:

$promise->then(function (ResponseInterface $response) use($request) {
    // onFulfilled callback
    echo 'The response is available, but it\'s not ok...';

    throw new HttpException('My error message', $request, $response);
}, function (Exception $e) {
    // onRejected callback
    echo 'An error happens, but it\'s ok...';

    return $exception->getResponse();
});

Calling the wait method on the promise will wait for the response or exception to be available and invoke callback provided in the then method.

Using the promise directly

If you don’t want to use the callback system, you can also get the state of the promise with $promise->getState() will return of one Promise::PENDING, Promise::FULFILLED or Promise::REJECTED.

Then you can get the response of the promise if it’s in FULFILLED state or trigger the exception of the promise if it’s in REJECTED state with $promise->wait(true) call.

Note

Read Promise for more information about promises.

Example

Here is a full example of a classic usage when using the sendAsyncRequest method:

use Http\Client\Exception;
use Http\Discovery\HttpAsyncClientDiscovery;

$httpAsyncClient = HttpAsyncClientDiscovery::find();

$promise = $httpAsyncClient->sendAsyncRequest($request);
$promise->then(function (ResponseInterface $response) {
   echo 'The response is available';

   return $response;
}, function (Exception $e) {
   echo 'An error happens';

   throw $e;
});

// Do some stuff not depending on the response, calling another request, etc ..
...

try {
    // We need now the response for our final treatment...
    $response = $promise->wait(true);
} catch (Exception $e) {
    // ...or catch the thrown exception
}

// Do your stuff with the response
...

Handling Errors

TODO: explain how to handle exceptions, distinction between network exception and HttpException.