Course: Symfony RESTful API: Hypermedia, Links & Bonuses (Course 5) Tutorial
Google for "HATEOAS PHP" to find a fun library that a friend of mine made. This library has a bundle that integrates it into Symfony: so click to view the BazingaHateoasBundle and go straight to its docs. Before we talk about what it does: get it installed.
Copy the composer require statement and then flip over to your terminal and paste that:
composer require willdurand/hateoas-bundle
This is a bundle, so grab the new bundle statement, open AppKernel
and pop that
at the bottom:
... lines 1 - 5 | |
class AppKernel extends Kernel | |
{ | |
public function registerBundles() | |
{ | |
$bundles = array( | |
... lines 11 - 21 | |
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(), | |
); | |
... lines 24 - 33 | |
} | |
... lines 35 - 52 | |
} |
Perfect. Currently, we have our own super sweet annotation system for adding links.
In Battle
, we use @Link
to create a programmer
link:
... lines 1 - 9 | |
/** | |
... lines 11 - 13 | |
* @Link( | |
* "programmer", | |
* route="api_programmers_show", | |
* params={"nickname": "object.getProgrammerNickname()"} | |
* ) | |
*/ | |
class Battle | |
... lines 21 - 138 |
Guess what! I completely stole that idea from this library. But now, to make our app
a little simpler and to get some new features, let's replace our @Link
code with
this library.
Go back to the library itself, and scroll down to the first coding example. This
uses an annotation system that looks pretty similar to ours. Copy the use
statement on top, open Battle
and paste that:
... lines 1 - 8 | |
use Hateoas\Configuration\Annotation as Hateoas; | |
... lines 10 - 141 |
Next, change the annotation to @Hateoas\Relation
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
... lines 16 - 20 | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
Keep programmer
: that will still be the link's rel
. But add href=@Hateoas\Route
and pass that the name of the route: api_programmers_show
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
* "programmer", | |
* href=@Hateoas\Route( | |
* "api_programmers_show", | |
... line 19 | |
* ) | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
Update params
to parameters
, and inside, set nickname
equal, and wrap the expression
in expr()
:
... lines 1 - 10 | |
/** | |
... lines 12 - 14 | |
* @Hateoas\Relation( | |
* "programmer", | |
* href=@Hateoas\Route( | |
* "api_programmers_show", | |
* parameters={"nickname"= "expr(object.getProgrammerNickname())"} | |
* ) | |
* ) | |
*/ | |
class Battle | |
... lines 24 - 141 |
That translates our annotation format to the one used by the bundle. And the result
is almost the same. Open BattleControllerTest
and copy the first method name:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
... lines 17 - 74 | |
} |
we have a test for a link near the bottom of this:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
{ | |
... lines 18 - 40 | |
$this->asserter()->assertResponsePropertyEquals( | |
$response, | |
'_links.programmer', | |
$this->adjustUri('/api/programmers/Fred') | |
); | |
... lines 46 - 48 | |
} | |
... lines 50 - 74 | |
} |
Change over to the terminal and, as long as Composer is done, run:
vendor/bin/phpunit --filter testPOSTCreateBattle
Check it out! It fails - but barely. This library still puts links under an
_links
key, but instead of listing the URLs directly, it wraps each inside an object
with an href
key. That's causes the failure.
Ok, fair enough. Let's fix that by updating the test to look for _links.programmer.href
:
... lines 1 - 6 | |
class BattleControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTCreateBattle() | |
{ | |
... lines 18 - 40 | |
$this->asserter()->assertResponsePropertyEquals( | |
$response, | |
'_links.programmer.href', | |
$this->adjustUri('/api/programmers/Fred') | |
); | |
... lines 46 - 48 | |
} | |
... lines 50 - 74 | |
} |
Run the test again:
vendor/bin/phpunit --filter testPOSTCreateBattle
And now we're green.
But guess what? It's no accident that this library used this exact format: with an
_links
key and an href
below that. This is a semi-official standard format called
HAL JSON.