Weave Code
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

willdurand/hateoas

Hateoas is a PHP library for building HATEOAS-friendly REST representations. Configure links and embedded resources via annotations/attributes, XML or YAML, with expression language support, URL generators, and serializers (HAL JSON/XML) for rich hypermedia APIs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require willdurand/hateoas:^3.14.0
    

    Ensure compatibility with PHP 8.5+ by updating your composer.json constraints:

    "require": {
        "php": "^8.1 || ^8.2 || ^8.3 || ^8.4 || ^8.5",
        "willdurand/hateoas": "^3.14.0"
    }
    
  2. First Use Case: Embedding Links in a Resource

    use WillDurand\Hateoas\Rest\Resource;
    use WillDurand\Hateoas\Link;
    
    $resource = new Resource('https://api.example.com/users/1');
    $resource->addLink(new Link('self', '/users/1'));
    $resource->addLink(new Link('collection', '/users'));
    
    return $resource->toArray(); // Returns HAL+JSON structure
    
  3. Where to Look First

    • Official Documentation (verify 3.14.0-specific examples).
    • src/ directory for core classes (Resource, Link, Collection).
    • Critical: Check CHANGELOG.md for PHP 8.5 fixes (e.g., SplObjectStorage deprecation resolved in PR #346).
    • New: Review examples/ folder (if added) for 3.14.0 patterns.
    • Tests: Validate PHP 8.5 compatibility in tests/ directory.

Implementation Patterns

1. Resource Representation (PHP 8.5 Safe)

  • Single Resource
    $user = new Resource('/users/1');
    $user->addLink('self', '/users/1');
    $user->addLink('edit', '/users/1/edit', [], 'PATCH');
    return $user->toArray(); // HAL+JSON output (PHP 8.5 verified)
    
  • Collection of Resources
    $users = new Collection('/users');
    $users->addLink('self', '/users');
    $users->addLink('create', '/users', [], 'POST');
    foreach ($userData as $user) {
        $users->addItem(new Resource('/users/' . $user['id']));
    }
    return $users->toArray();
    

2. Dynamic Link Generation (PHP 8.5 Optimized)

Use closures for runtime resolution (fully compatible in 3.14.0):

$resource->addLink('self', function () use ($userId) {
    return "/users/{$userId}";
});

Note: Avoid SplObjectStorage in custom logic to prevent legacy warnings.

3. Integration with Laravel Controllers

  • API Resource Transformation
    use App\Http\Resources\UserResource;
    use WillDurand\Hateoas\Rest\Resource as HateoasResource;
    
    public function show(User $user)
    {
        $resource = new HateoasResource('/users/' . $user->id);
        $resource->addLink('self', route('users.show', $user));
        $resource->addLink('edit', route('users.edit', $user), [], 'PATCH');
    
        return new UserResource($user, $resource->toArray());
    }
    
  • Middleware for Global Links (PHP 8.5 Compatible)
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        if ($response->isSuccessful() && $request->wantsJson()) {
            $resource = new Resource($request->url());
            $resource->addLink('self', $request->url());
            $response->setData(array_merge($response->getData(), [
                '_links' => $resource->getLinks()
            ]));
        }
        return $response;
    }
    

4. Embedding Sub-Resources (PHP 8.5 Warning-Free)

$user = new Resource('/users/1');
$user->addLink('self', '/users/1');
$user->addEmbedded('posts', new Collection('/users/1/posts'));

Tip: Use lazy-loading to avoid SplObjectStorage issues:

$user->addEmbedded('posts', function () {
    return (new Collection("/users/1/posts"))->setMaxDepth(1);
});

Gotchas and Tips

Pitfalls

  1. PHP 8.5 SplObjectStorage Deprecation (RESOLVED)

    • Old Issue: Previous versions triggered warnings in PHP 8.5.
    • Fix: Update to ^3.14.0 (includes PR #346).
    • Custom Code: If extending, avoid SplObjectStorage entirely. Use ArrayObject or arrays.
  2. Link Relativization (Unchanged) Links default to absolute URLs. Use Laravel’s route() or url() helpers:

    $link = new Link('self', route('users.show', $user)); // Laravel-aware
    
  3. Circular References in Embedded Resources

    • Risk: Infinite loops in deeply nested embeds.
    • Solution: Limit depth or lazy-load:
      $user->addEmbedded('posts', function () {
          return (new Collection("/users/1/posts"))->setMaxDepth(1);
      });
      
  4. HTTP Method Conflicts

    • Links with methods (e.g., DELETE) may not render in all HAL+JSON parsers.
    • Test: Validate with tools like HAL Browser.

Debugging Tips

  • Inspect Links for PHP 8.5 Compatibility
    $links = $resource->getLinks();
    foreach ($links as $rel => $link) {
        error_log("Link [$rel]: " . $link->getHref());
    }
    
  • Validate HAL+JSON Output Use json_encode($resource->toArray(), JSON_PRETTY_PRINT) to catch serialization issues.
  • Check Route Resolution Ensure all href values resolve in Laravel’s router:
    if (!Route::has($resource->getLink('self')->getHref())) {
        throw new \RuntimeException("Route not found");
    }
    

Extension Points

  1. Custom Link Types (PHP 8.5 Features) Leverage PHP 8.5’s named arguments:

    class ApiLink extends Link
    {
        public function __construct(
            string $rel,
            string $href,
            array $attributes = [],
            ?string $method = null,
            ?string $name = null,
            ?string $title = null,
            bool $isTemplated = false,
        ) {
            parent::__construct($rel, $href, $attributes, $method, $name, $title);
            $this->isTemplated = $isTemplated;
        }
    }
    
  2. Laravel Service Provider Binding Bind the updated package:

    public function register()
    {
        $this->app->singleton('hateoas.resource', function () {
            return new Resource('');
        });
    }
    
  3. Format-Specific Rendering Override Resource::toArray() for JSON:API:

    $resource->setData(['id' => 1, 'name' => 'John']);
    $resource->toJsonApiArray(); // Custom method
    
  4. Caching Links with RouteServiceProvider Pre-generate links to avoid runtime resolution:

    $linkGenerator = app()->make(\Illuminate\Routing\Router::class);
    $selfLink = $linkGenerator->to('users.show', ['user' => $user->id]);
    $resource->addLink('self', $selfLink);
    
  5. PHP 8.5 Performance Tip Use match expressions for link type validation:

    $method = match ($link->getMethod()) {
        'DELETE' => 'delete',
        'PATCH' => 'update',
        default => 'get',
    };
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky