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

Laravel Endpoint Resources Laravel Package

spatie/laravel-endpoint-resources

Abandoned package that adds controller/action-based URL links to Laravel API resources and collection meta. Includes traits to generate “show/edit/update/delete” item links and “index/create/store” collection links automatically.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-endpoint-resources
    

    Publish the config (if needed):

    php artisan vendor:publish --provider="Spatie\ResourceLinks\ResourceLinksServiceProvider"
    
  2. Basic Usage: Extend your JsonResource with the HasLinks trait:

    use Spatie\ResourceLinks\HasLinks;
    
    class UserResource extends JsonResource
    {
        use HasLinks;
    
        public function toArray($request): array
        {
            return [
                'id' => $this->id,
                'name' => $this->name,
                'links' => $this->links(), // Auto-generates links
            ];
        }
    }
    
  3. First Use Case: Automatically generate API links for a User resource in a show endpoint:

    public function show(User $user)
    {
        return new UserResource($user);
        // Returns: { "id": 1, "name": "John", "links": { "self": "/users/1", "edit": "/users/1/edit", ... } }
    }
    

Implementation Patterns

Controller-Based Link Generation

  1. Default Controller Mapping: The package auto-detects RESTful controller actions (e.g., index, show, store, update, destroy) and generates links like:

    $this->links(); // Returns: { "self": "/users/1", "edit": "/users/1/edit", ... }
    
  2. Custom Controller Actions: Define explicit actions in your ResourceLinks config or via the trait:

    use Spatie\ResourceLinks\HasLinks;
    
    class UserResource extends JsonResource
    {
        use HasLinks;
    
        public function getLinks()
        {
            return [
                'custom-action' => route('users.custom', $this->id),
            ];
        }
    }
    
  3. Nested Resource Links: For nested resources (e.g., Post under User), use the nested method:

    $this->links()->nested('posts'); // Generates: { "posts": "/users/1/posts" }
    
  4. Conditional Links: Dynamically include/exclude links based on user roles or resource state:

    public function toArray($request): array
    {
        return [
            'links' => $this->links()->onlyIf(
                fn () => $request->user()->can('edit-users')
            ),
        ];
    }
    
  5. API Versioning: Leverage Laravel’s route model binding with versioned routes:

    Route::apiResource('v1/users', UserController::class);
    // Links will auto-respect the `v1` prefix.
    

Workflows

  1. API Documentation: Use the generated links in OpenAPI/Swagger docs to auto-populate endpoints:

    paths:
      /users/{id}:
        get:
          responses:
            200:
              $ref: '#/components/responses/User'
    components:
      responses:
        User:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
                properties:
                  links:
                    $ref: '#/components/schemas/Links'
    
  2. Frontend Integration: Pass links to Vue/React for dynamic navigation:

    // Example: Fetch user data and use `links.self` for redirects.
    const { data: user } = await api.get(`/users/${id}`);
    router.push(user.links.self);
    
  3. Admin Panels: Integrate with Laravel Nova or Filament for auto-generated CRUD links:

    // Nova Tool
    public function fields(Request $request)
    {
        return array_merge(parent::fields($request), [
            Link::make('Edit', $this->resource->links()->edit),
        ]);
    }
    
  4. GraphQL Wrappers: Expose links in GraphQL responses via Laravel GraphQL:

    type User {
        id: ID!
        name: String!
        links: Links!
    }
    

Integration Tips

  1. Route Caching: Cache routes to improve link generation performance:

    Route::cache();
    // Run `php artisan route:cache` after changes.
    
  2. Route Model Binding: Ensure your routes use implicit binding for consistency:

    Route::apiResource('users', UserController::class)->except(['create', 'edit']);
    
  3. Testing: Mock links in unit tests:

    $resource = new UserResource(new User());
    $resource->shouldReceive('links')->andReturn(['self' => '/mock-url']);
    
  4. API Rate Limiting: Apply rate limits to link endpoints (e.g., edit routes) separately:

    Route::middleware('throttle:60,1')->group(function () {
        Route::patch('/users/{user}', [UserController::class, 'update']);
    });
    

Gotchas and Tips

Pitfalls

  1. Abandoned Package:

  2. Route Name Conflicts:

    • If routes share names (e.g., users.edit and posts.edit), links may resolve incorrectly. Use absolute URLs or unique route names:
      Route::name('users.edit')->patch('/users/{user}');
      Route::name('posts.edit')->patch('/posts/{post}');
      
  3. Missing Controller Actions:

    • The package assumes standard RESTful actions. For non-standard methods (e.g., approve), define them explicitly:
      protected function getLinks()
      {
          return [
              'approve' => route('users.approve', $this->id),
          ];
      }
      
  4. Circular References:

    • Avoid infinite loops when linking nested resources with shared models:
      // UserResource links to PostResource, which links back to UserResource.
      // Solution: Use `only()` to limit links.
      $this->links()->only(['self', 'edit']);
      
  5. Localization Issues:

    • Route names with localization (e.g., users.{locale}) may break link generation. Use absolute paths or static route names:
      Route::name('users.edit')->patch('/users/{user}/edit');
      

Debugging

  1. Inspect Generated Links: Dump links to debug resolution:

    dd($this->links()->toArray());
    
  2. Route Debugging: List all routes to verify names:

    php artisan route:list
    
  3. Missing Routes: If a link returns null, check:

    • The route exists (php artisan route:list).
    • The route name is correct (case-sensitive).
    • The model is bound correctly (e.g., {user} vs {id}).

Configuration Quirks

  1. Default Excludes: The package excludes create and store links by default for show resources. Override in config:

    'excluded_actions' => [
        'create',
        // 'store', // Uncomment to include.
    ],
    
  2. Custom Link Methods: Extend the trait to add methods:

    class UserResource extends JsonResource
    {
        use HasLinks;
    
        public function links()
        {
            return parent::links()->merge([
                'profile' => route('users.profile', $this->id),
            ]);
        }
    }
    
  3. Query Parameters: Preserve query params in links (e.g., for pagination):

    $this->links()->withQueryParams(['page' => 2]);
    

Extension Points

  1. Custom Link Providers: Create a service provider to add global link logic:

    class CustomLinkProvider
    {
        public function __invoke($resource)
        {
            return [
                'webhook' => route('users.webhook', $resource->id),
            ];
        }
    }
    

    Register in AppServiceProvider:

    ResourceLinks::extend('webhook', CustomLinkProvider::class);
    
  2. Dynamic Link Resolution: Use closures for runtime link generation:

    $this->links()->merge([
        'download' => function () {
            return route('users.download', $this->id, [
                'format' => 'pdf',
            ]);
        },
    ]);
    
  3. Link Formatting: Modify link output (e.g., add API version):

    public function toArray($request
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport