PHPackages                             hedgehog-lab/laravel-resourceful - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. hedgehog-lab/laravel-resourceful

ActiveLibrary[API Development](/categories/api)

hedgehog-lab/laravel-resourceful
================================

Laravel API Resources supercharged to get rid of N+1 problems.

v3.0.0(1mo ago)0138↓36.7%MITPHP ^8.2

Since May 15Compare

[ Source](https://github.com/hedgehoglab-engineering/laravel-resourceful)[ Packagist](https://packagist.org/packages/hedgehog-lab/laravel-resourceful)[ RSS](/packages/hedgehog-lab-laravel-resourceful/feed)WikiDiscussions Synced 1w ago

READMEChangelog (1)Dependencies (4)Versions (5)Used By (0)

Laravel Resourceful
===================

[](#laravel-resourceful)

Package that helps you use Laravel API Resources without killing your database! Say goodbye to N+1 👋

The Problem
-----------

[](#the-problem)

Picture a User model that has an "avatar" relation to a File model:

```
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'avatar_url' => $this->avatar->url,
        ];
    }
}
```

To return a list of users from our API, we could have such a controller action:

```
namespace App\Http\Controllers;

use App\Models\User;

class UserController extends \Illuminate\Routing\Controller
{
    public function index()
    {
        return UserResource::collection(User::paginate());
    }
}
```

In the example above:

- if there is 1 user in our database, 2 queries will be executed
- if there are 100 users in our database, 101 queries will be executed - 1 to get the user, and then 1 query for each avatar for each user

We have a classic N+1 problem. The usual solution in Laravel is to perform eager loading within the controller:

```
namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Routing\Controller;

class UserController extends Controller
{
    public function index()
    {
        return UserResource::collection(User::query()->with('avatar')->paginate());
    }
}
```

This works, but has few problems:

- requires the controller to be aware of inner structure of each API resource
    - in the example above, our controller had to know that we need access to avatar relation in the User resource
    - this is hard to maintain, as we need to keep multiple places in sync
- it's hard to make the eager loading conditional
    - in the example above, we may want to return the avatar\_url only for users on a certain membership plan
    - and if we won't be returning the avatar\_url, then why load the Avatar model in the first place?
- it's hard to keep the eager loading DRY, since it is tied to the controller and not the API resource
    - imagine an ArticleResource, that returns a list of related reviewers, each reviewer being a UserResource
    - fetching the Articles in controller would need to eager load not just the related users, but also the avatars for each user
- since the eager loading is spread in multiple places, any N+1 optimisation is done for each place separately and benefits only that place
    - other endpoints relying on affected API resource will still have N+1 problem

This package fixes all those problems and makes the N+1 problem within your API a thing of the past!

Installation
------------

[](#installation)

using composer:

```
composer require hedgehog-lab/laravel-resourceful
```

Usage
-----

[](#usage)

This package is a drop in replacement for the official API Resources. Instead of extending the builtin `Illuminate\Http\Resources\Json\JsonResource` we extend `HedgehogLab\Http\Resources\Json\JsonResource`.

Continuing with the example above, we get:

```
namespace App\Http\Resources;

use HedgehogLab\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'avatar_url' => $this->avatar->url,
        ];
    }
}
```

Of course, this doesn't change anything and things still work as they did with N+1 problem, however this first step allows you to easily switch over to this package.

There are few ways now to supercharge your API resource.

### Preloads method

[](#preloads-method)

First way is to select the relations for eager loading in a dedicated `preloads` method. You should return one or more "deferred resources", which can be easily created by calling `preload` helper with a list of relations you want loaded. The `preloads` method can optionally accept a Laravel Request as its first argument. Within the `preloads` method we have access to the Eloquent model being resolved. This allows us to introduce conditional logic for preloading specific relations based on request parameters / model attributes.

```
namespace App\Http\Resources;

use Illuminate\Http\Request;
use HedgehogLab\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function preloads()
    {
        return $this->preload('avatar');
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'avatar_url' => $this->avatar->url,
        ];
    }
}
```

Now before the `toArray` is called, the `avatar` relation will be loaded for all the users in collection, so we've got full access to `$this->avatar` without issuing further queries.

[More examples can be seen in the tests.](tests/Integration/Resources/Super/FullLibrary/Preload/BookResource.php)

### Use callback method

[](#use-callback-method)

Second way is to provide a callback which will be called with the resolved relations.

```
namespace App\Http\Resources;

use Illuminate\Http\Request;
use HedgehogLab\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'avatar_url' => $this->use('avatar', fn ($avatar) => $avatar->url),
        ];
    }
}
```

Now when `toArray` is called, the `avatar` relation hasn't been loaded yet. Our code in the `toArray` method will execute for all the users in collection, and each call to the `use` method will queue a relation to be loaded. We'll then resolve all the queued relations for all users in the most optimal way, and invoke the callback function with resolved relations.

[More examples can be seen in the tests.](tests/Integration/Resources/Super/FullLibrary/Callback/BookResource.php)

### Inline method

[](#inline-method)

Third way is to use an inline shortcut which is very convenient for loading one or many nested API Resources.

```
namespace App\Http\Resources;

use Illuminate\Http\Request;
use HedgehogLab\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'avatar' => $this->one('avatar', AvatarResource::class),
        ];
    }
}

class AvatarResource extends JsonResource
{
    public function preloads()
    {
        return $this->preload('file');
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'width' => $this->width,
            'height' => $this->height,
            'url' => $this->file->s3Url(),
        ];
    }
}
```

In the example above, we have introduced a nested resource, where a UserResource embeds a separate AvatarResource. Each resource is responsible for eager loading its own relations, and together all relations are loaded in most optimal way.

[More examples can be seen in the tests.](tests/Integration/Resources/Super/FullLibrary/Inline/BookResource.php)

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance90

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity61

Established project with proven stability

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~382 days

Total

4

Last Release

49d ago

Major Versions

1.x-dev → 2.x-dev2025-03-07

2.x-dev → 3.x-dev2026-07-06

PHP version history (2 changes)1.x-devPHP ^8.1 || ^8.2

2.x-devPHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/967f8fc19e4b61cc07cd6d69357e2424171236c2f903c23ba6675ceda4f5708e?d=identicon)[will-c-f](/maintainers/will-c-f)

---

Tags

laraveleager-loadingnetsellsapi resourcehedgehog-lab

### Embed Badge

![Health badge](/badges/hedgehog-lab-laravel-resourceful/health.svg)

```
[![Health](https://phpackages.com/badges/hedgehog-lab-laravel-resourceful/health.svg)](https://phpackages.com/packages/hedgehog-lab-laravel-resourceful)
```

###  Alternatives

[statamic/cms

The Statamic CMS Core Package

4.9k3.8M1.2k](/packages/statamic-cms)[darkaonline/l5-swagger

OpenApi or Swagger integration to Laravel

2.9k38.9M151](/packages/darkaonline-l5-swagger)[knuckleswtf/scribe

Generate API documentation for humans from your Laravel codebase.✍

2.3k15.0M69](/packages/knuckleswtf-scribe)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[scriptdevelop/whatsapp-manager

Paquete para manejo de WhatsApp Business API en Laravel

793.9k](/packages/scriptdevelop-whatsapp-manager)[ecotone/laravel

Ecotone for Laravel — CQRS, Event Sourcing, Sagas, Durable Workflows, and Outbox on top of Laravel Queue, via PHP attributes.

21327.3k4](/packages/ecotone-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
