Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Hateoas Laravel Package

gointegro/hateoas

Laravel package for building HATEOAS-compliant REST APIs. It adds hypermedia links and embedded relationships to Eloquent resources, supports HAL and JSON:API formats, and helps you ship self-descriptive, discoverable APIs with minimal boilerplate.

Deep Wiki
Context7

Getting Started

gointegro/hateoas is a Laravel 4/5-era package for exposing Eloquent models as HATEOAS/JSON API resources. Treat it as a legacy integration: the last release was in 2015, so the first task is proving it installs and boots against your Laravel version before designing around it.

Minimal path:

  1. Install it:

    composer require gointegro/hateoas
    
  2. Register the service provider manually. The package predates Laravel package auto-discovery, so add it to config/app.php:

    'providers' => [
        // ...
        GoIntegro\Hateoas\HateoasServiceProvider::class,
    ],
    
  3. Publish and inspect the config:

    php artisan vendor:publish --provider="GoIntegro\Hateoas\HateoasServiceProvider"
    

    On older Laravel 4 installations this may be php artisan config:publish gointegro/hateoas.

  4. Look first at:

    • config/hateoas.php — resource mapping, media type/serializer, pagination settings.
    • src/GoIntegro/Hateoas/Resources/Resource.php — base resource API, link helpers, and how the wrapped model is exposed.
    • ResourceCollection — collection/pagination behavior.
    • The package README and tests — the fastest source of working examples for your installed version.
  5. Wire one model end-to-end. A typical first resource:

    namespace App\Resources;
    
    use GoIntegro\Hateoas\Resources\Resource;
    
    class PostResource extends Resource
    {
        public function getLinks()
        {
            $post = $this->resource; // accessor may differ by version; check the base class
    
            return [
                new Link('self', route('posts.show', $post->id)),
                new Link('author', route('users.show', $post->user_id)),
            ];
        }
    }
    
  6. Register the model-to-resource mapping, if your version requires it:

    // config/hateoas.php
    return [
        'resources' => [
            App\Post::class => App\Resources\PostResource::class,
        ],
    ];
    
  7. Return it from a controller:

    public function show($id)
    {
        return new PostResource(Post::findOrFail($id));
    }
    

The first useful milestone is a GET /posts/{id} response containing data, type, id, attributes, and a links object with a working self URL. Once that works, add a collection and one relationship.

Implementation Patterns

One resource class per model, with a shared base resource. Keep link and serialization logic out of Eloquent models. Use a base class for common links such as self, and override or extend for model-specific links:

abstract class BaseResource extends Resource
{
    protected function selfLink()
    {
        return new Link('self', route($this->routeBaseName().'.show', $this->resource->id));
    }
}

Authorization-aware links. In HATEOAS, the presence of a link is an API contract. Do not emit edit or delete links unless the current user can perform those actions:

public function getLinks()
{
    $links = [new Link('self', route('posts.show', $this->resource->id))];

    if (Gate::allows('update', $this->resource)) {
        $links[] = new Link('edit', route('posts.edit', $this->resource->id));
    }

    return $links;
}

This keeps the API honest and prevents clients from discovering actions they cannot use.

Collections and pagination. Use the package's collection class rather than returning raw arrays. Pagination links (first, prev, next, last) should be generated by the same URL layer as self:

public function index()
{
    return new PostCollection(Post::query()->paginate(25));
}

If your version supports a paginator adapter, use it so page metadata and links stay consistent with the configured media type.

Relationship inclusion and N+1 avoidance. HATEOAS clients often request embedded resources via ?include=author,comments. Parse that parameter in the controller or a query object, eager-load exactly those relations, and let the resource layer serialize them. Do not lazily walk relations inside getLinks() or relationship methods without eager loading, or a collection endpoint will produce an N+1 storm.

Write endpoints. If your version includes a hydrator, use it to translate JSON API documents into model attributes, but validate before hydration and persist inside a transaction. If the hydrator is incomplete or version-specific, keep a thin mapper in the controller and use the resource only for output:

$payload = $request->json()->all();
$validator = Validator::make($payload['data']['attributes'] ?? [], [
    'title' => 'required|string|max:255',
]);
$validator->validate();

$post = Post::create($payload['data']['attributes']);
return new PostResource($post);

Content negotiation and middleware. Register any package middleware in the correct order, especially if it handles Accept headers or JSON API media types. A request with the wrong Accept header may produce an empty body or a 406 rather than a helpful error. Test with the exact media type your config advertises:

curl -H "Accept: application/vnd.api+json" http://localhost/posts/1

Testing pattern. Assert structure, not exact URLs, and assert link presence separately:

$response->assertStatus(200);
$response->assertJsonStructure([
    'data' => [
        'type',
        'id',
        'attributes' => ['title', 'body'],
        'links' => ['self'],
    ],
]);

Use URL::forceRootUrl() in CLI tests if link generation depends on the request host.

Keep resources presentation-only. Resources should compose links and expose attributes; business rules belong in policies, services, or query objects. This makes the API layer replaceable if you later migrate off the package.

Gotchas and Tips

  • Legacy compatibility is the main risk. This package targets Laravel 4/5 and PHP 5.x-era code. Modern Laravel and PHP 8 will likely hit removed helpers, changed contracts, or Composer constraint conflicts. Budget for a fork or a compatibility shim before committing.
  • No package auto-discovery. If the provider is not registered manually, you will get "class not found" or missing config errors that look like routing problems.
  • Config caching hides mapping mistakes. After changing the model-to-resource map, run php artisan config:clear (and config:cache again if used). A stale cached config is a common cause of "my new resource is ignored."
  • The wrapped-model accessor varies by version. Check Resource.php rather than guessing between $this->resource, $this->entity, and $this->getResource(). Copy the pattern from the package tests.
  • Link generation needs request context. route() produces absolute URLs based on the current request. In queue workers, console commands, or tests without a request, set URL::forceRootUrl() and URL::forceScheme() explicitly, or links will point at http://localhost.
  • Beware relationship recursion. Post -> author -> posts -> author can recurse indefinitely if relationships are serialized eagerly. Use explicit includes, depth limits, or a serializer that only embeds requested relationships.
  • Pagination links behind proxies and load balancers. Without trusted proxy configuration and forced schemes, generated links may be http instead of https or use an internal hostname. Fix at the URL generator/proxy layer, not by post-processing strings.
  • Error responses are not automatic. Package exceptions may not match your application's JSON error format. Catch them in App\Exceptions\Handler and convert to the same media type and error document shape as successful responses.
  • Caching absolute links is fragile. If you cache full responses, include host/scheme in the cache key or cache relative representations and expand links per request.
  • Extension points to prefer: subclass Resource and ResourceCollection, override link generation, bind a custom serializer/hydrator if the package exposes container bindings, and keep custom behavior in your application namespace rather than editing vendor code.
  • Assess exit cost early. Because the package is unmaintained, keep resource classes thin and avoid leaking package-specific types into controllers, jobs, or domain code. That makes a later replacement with a modern serializer or JSON API library much cheaper.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin