Installation:
composer require willdurand/hateoas-bundle
Enable the bundle in config/bundles.php:
return [
// ...
WillDurand\Hateoas\Bundle\HateoasBundle::class => ['all' => true],
];
First Use Case:
use WillDurand\Hateoas\Representation\CollectionRepresentation;
use WillDurand\Hateoas\Representation\PaginatedRepresentation;
use WillDurand\Hateoas\Representation\RepresentationInterface;
// Example: Wrap a collection with links
$representation = new CollectionRepresentation($items, [
'self' => ['route' => 'api_items', 'routeParameters' => ['page' => 1]],
'next' => ['route' => 'api_items', 'routeParameters' => ['page' => 2]],
]);
Where to Look First:
src/Representation/ for core classes (RepresentationInterface, CollectionRepresentation, etc.).src/Builder/ for dynamic link generation.Embedding Links in Responses:
RepresentationInterface to attach links to data:
$representation = new Representation($data, [
'self' => ['route' => 'api_show', 'routeParameters' => ['id' => $id]],
'edit' => ['route' => 'api_edit', 'routeParameters' => ['id' => $id]],
]);
return $this->json($representation);
Pagination with HATEOAS:
PaginatedRepresentation for paginated APIs:
$paginated = new PaginatedRepresentation(
$items,
['self' => ['route' => 'api_items', 'routeParameters' => ['page' => 1]]],
$totalItems,
$pageSize
);
Dynamic Link Generation:
Builder\BuilderInterface to generate links programmatically:
$builder = $this->get('hateoas.builder');
$link = $builder->uriFor('api_show', ['id' => $id]);
Embedding Sub-Representations:
$user = new Representation($userData, ['self' => $selfLink]);
$representation = new Representation($data, [
'self' => $selfLink,
'user' => $user,
]);
Integration with Symfony Serializers:
Hateoas\Serializer\HateoasSerializer to normalize representations:
# config/packages/hateoas.yaml
hateoas:
serializer:
enabled: true
# config/packages/fos_rest.yaml
fos_rest:
view:
formats:
json: true
mime_types:
json: ['application/json', 'application/hal+json']
LinkProviderInterface for domain-specific links.Route Resolution:
routeParameters.Circular References:
Hateoas\Serializer\HateoasSerializer with ignore_circular_references: true in config.Overhead in Simple APIs:
Deprecated Methods:
addLink instead of setLink).Enable Debug Mode:
# config/packages/hateoas.yaml
hateoas:
debug: true
Logs link generation and serialization issues.
Validate Representations:
Use RepresentationInterface::getLinks() to inspect generated links:
$links = $representation->getLinks();
dump($links);
Custom Representation Classes:
Extend Representation for domain-specific logic:
class PostRepresentation extends Representation {
public function __construct($data, array $links = []) {
parent::__construct($data, $links);
$this->addLink('comments', ['route' => 'api_post_comments', 'routeParameters' => ['id' => $data['id']]]);
}
}
Link Providers:
Implement LinkProviderInterface for dynamic links:
class UserLinkProvider implements LinkProviderInterface {
public function getLinks($resource) {
return [
'profile' => ['route' => 'api_user_profile', 'routeParameters' => ['id' => $resource['id']]],
];
}
}
Register in services:
services:
App\LinkProvider\UserLinkProvider:
tags: [hateoas.link_provider]
Serializer Groups: Use Symfony’s serializer groups to control which fields/links are included:
$representation = new Representation($data, $links, ['groups' => ['api']]);
Disable HATEOAS Globally:
hateoas:
enabled: false
Useful for non-RESTful parts of the app.
Custom Link Templates:
Override default link templates in config/packages/hateoas.yaml:
hateoas:
link_templates:
self: 'api_{resource}_self'
next: 'api_{resource}_next'
How can I help you explore Laravel packages today?