Paginating Laravel API resources in InertiaJS applications

Later edit: Paginating Laravel API resources now works as Reinink added support for Responsable props.

If you’re a Laravel developer working with InertiaJS, there’s a good chance you played around with PingCRM, the application Jonathan build to illustrate how InertiaJS works. If not, I encourage you to have a look over it as it helps a lot in figuring out how Inertia should be used.

Because the default Laravel pagination does not work well with Inertia, in PingCRM the LengthAwarePaginator was swapped with a custom one which does work when paginating Eloquent models, but fails to do so when using API resources. Don’t get bummed out, there are a few solutions:

Use the transform(callback) method.

This will loop through the collection and return an API resource.

return Inertia::render('Users/Index', [
    'filters' => Request::all('search', 'trashed'),
    'users' => User::query()->paginate()
        ->transform(function ($user) {
            return UserResource::make($user);
        }),
]);

Create dedicated API collection resources

I don’t fancy this one as you’ll probably end up with two resource classes for each eloquent model you need to paginate – but maybe that makes sense for your application.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return [
            'data' => UserResource::collection($this->collection),
            'links' => $this->resource->links()
        ];
    }
}

The way I chose to do it, create a custom PaginatedCollection class

The usage looks something like this:

return Inertia::render('Users/Index', [
    'filters' => Request::all('search', 'trashed'),
    'users' => new PaginatedCollection(User::query()->paginate(), UserResource::class)
]);

The class does pretty much what a dedicated collection resource would do, except you no longer need to create a new collection class for every eloquent model.

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class PaginatedCollection extends ResourceCollection
{
    private $resourceClass;

    public function __construct($resource, $resourceClass)
    {
        parent::__construct($resource);

        $this->resource = $this->collectResource($resource);
        $this->resourceClass = $resourceClass;
    }

   
    public function toArray($request)
    {
        return [
            'data' => $this->resourceClass::collection($this->collection),
            'links' => $this->resource->links(),
        ];
    }
}

It extends Laravel’s ResourceCollection and receives the collection and the resource class as constructor parameters and then it maps out the collection you passed in.

Keep in mind that every proposed solution makes use of a custom LengthAwarePaginator as seen in PingCRM.

In case I missed something and there’s a cleaner way to do it, please let me know in the comments 🙂

Subscribe to get my latest blog posts.