A lightweight client for consuming and manipulating Hypertext Application Language (HAL) resources.

v3.4.2 2017-03-10 18:57 UTC


A lightweight PHP client for consuming and manipulating Hypertext Application Language (HAL) resources.

Build Status Coverage Status


Install the latest version with Composer.

composer require jsor/hal-client

Check the Packagist page for all available versions.

HTTP Client dependency

The Hal client requires a HttpClientInterface implementation which can handle PSR-7 requests and responses.

To use the default implementations shipped with this library, you need to install Guzzle 6 or Guzzle 5.

composer require guzzlehttp/guzzle:"^5.0||^6.0"

URI template handling

In order to expand URI templates in HAL links, you must either provide a global \uri_template function (e.g. by installing the uri_template extension) or install the guzzlehttp/guzzle package (version ^5.0 or ^6.0).


We will use Propilex as an example API endpoint.

Create the client

At a first step, we setup a HalClient instance.

use Jsor\HalClient\HalClient;

$client = new HalClient('http://propilex.herokuapp.com');

We can now set additional headers (eg. an Authorization header) which are sent with every request.

$client = $client->withHeader('Authorization', 'Bearer 12345');

Note, that a client instance is immutable, which means, any call to change the state of the instance returns a new instance leaving the original instance unchanged.

// Wrong!
$client->withHeader('Authorization', '...');
$resource = $client->get('/protected');

// Correct!
$client = $client->withHeader('Authorization', '...');
$resource = $client->get('/protected');

Browse the API

To start browsing through the API, we first get the root resource.

/** @var \Jsor\HalClient\HalResource $rootResource */
$rootResource = $client->root();

We now follow the p:documents link.

/** @var \Jsor\HalClient\HalLink $documentsLink */
$documentsLink = $rootResource->getFirstLink('documents');

$documentsResource = $documentsLink->get();

$totalDocuments = $documentsResource->getProperty('total');

foreach ($resource->getResource('documents') as $document) {
    echo $document->getProperty('title') . PHP_EOL;

If there is a second page with more documents, we can follow the next link.

if ($documentsResource->hasLink('next')) {
    $nextDocumentsResource = $documentsResource->getFirstLink('next')->get();

Ok, let's create a new document.

$newDocument = $documentsResource->post([
    'body' => [
        'title' => 'Sampl document',
        'body'  => 'Lorem ipsum'

Oh noes! A typo in the document title. Let's fix it.

$changedDocument = $newDocument->put([
    'body' => [
        'title' => 'Sampe document',
        'body'  => $newDocument->getProperty('body')

Damn, we give up.



Copyright (c) 2015-2017 Jan Sorgalla. Released under the MIT License.