talentrydev/hateoas-bundle
A Symfony bundle for building HATEOAS-compliant APIs, adding hypermedia links and relations to your resources so clients can discover and navigate endpoints dynamically. Integrates with your existing serialization to expose self-descriptive, discoverable responses.
Read this first: this is not a Laravel package. talentrydev/hateoas-bundle is a Symfony bundle — specifically a republished/forked copy of willdurand/BazingaHateoasBundle, which wires the willdurand/hateoas library into the Symfony full-stack framework (service container, serializer, bundle registration in AppKernel/bundles.php). There is no ServiceProvider, no config/*.php publish target, and no Laravel-facing API. As a Laravel developer you should treat this repository as a reference implementation, not a dependency.
Given that, the useful "getting started" path is:
composer require willdurand/hateoas is what actually does the work. The bundle only contributes Symfony DI glue you will rewrite anyway.DependencyInjection/Configuration.php and Resources/config/*.xml to understand how the upstream library is meant to be configured (metadata cache, serializer, expression language for link hrefs). That is the only thing this repo teaches you that the library docs don't._links and _embedded, annotate it (or configure it), and serialize it to HAL JSON instead of hand-writing link arrays in every controller.A realistic Laravel smoke test:
// composer require willdurand/hateoas
$hateoas = \Hateoas\HateoasBuilder::create()->build();
$hateoas->serialize($order, 'json'); // produces _links / _embedded
If that works, you have 90% of what the bundle offered, without a Symfony kernel.
Direct library usage inside a Laravel service provider. Bind a singleton built by HateoasBuilder and inject it into a base controller or a response macro. This is the closest analogue to what the bundle does with bazinga_hateoas.serializer.
// AppServiceProvider::register()
$this->app->singleton(\Hateoas\Hateoas::class, function () {
return \Hateoas\HateoasBuilder::create()
->setExpressionEvaluator(new \Symfony\Component\ExpressionLanguage\ExpressionLanguage())
->build();
});
// Response macro
Response::macro('hateoas', function ($object) {
return response()->json(
json_decode(app(\Hateoas\Hateoas::class)->serialize($object, 'json'), true)
);
});
Annotate models, keep controllers thin. The library's model is annotation/attribute-driven (@Hateoas\Relation, @Hateoas\Embedded). Use it on DTOs or Eloquent models so link construction lives with the resource, not in ten controllers. Prefer dedicated resource/DTO classes over Eloquent models — the metadata cache keys on class + file mtime and churns badly on frequently edited models.
Compose with API Resources rather than replacing them. A common pattern: build the payload with JsonResource, then post-process to inject _links. HATEOAS relations are about behavior (what can I do next), not field shaping — let Resources own the shape and Hateoas own the links.
Mirror the bundle's config surface in a config file. The bundle exposes roughly bazinga_hateoas.metadata.cache (e.g. a file cache under %kernel.cache_dir%) and serializer settings. Reproduce that as config/hateoas.php with metadata.cache.path => storage_path('framework/hateoas') plus a cache: true toggle per environment — you want it off in local and on in production.
Use relation providers for cross-cutting links. If every resource needs self and collection links derived from route names, write one relation provider and apply it globally instead of repeating annotations. This also keeps route-name changes in one place.
willdurand/hateoas leans on symfony/serializer and symfony/expression-language. Those install fine in a Laravel app, but you inherit a second serializer stack alongside Laravel's, with different normalization semantics. Budget time for the boundary; don't try to unify them.bazinga_hateoas namespace and config root will mislead you in copy-paste. Anything you find in this repo's docs assumes AppKernel::registerBundles(), services.xml, and %kernel.cache_dir%. Translating that to config/app.php + AppServiceProvider is manual, and most tutorials you'll find online are for the Symfony bundle, not the library.href expression like expr("/orders/" ~ object.getId()) throws deep inside the evaluator with an unhelpful message. Wrap serialization in a test that asserts the exact _links structure; don't eyeball it.RelationProviders, a custom UrlGenerator (this is where you'd plug Laravel\UrlGenerator/route() in place of Symfony's router — the bundle's bazinga_hateoas.url_generator service is the exact seam), and the expression evaluator. The URL generator swap is mandatory in Laravel, not optional.spatie/laravel-fractal (with its serializer layer) or plain JsonResource + a small links() helper covers most real HATEOAS needs with none of this dependency baggage. Reach for willdurand/hateoas only if you specifically want its annotation model and relation-provider machinery.How can I help you explore Laravel packages today?