Extending Laravel Scout with Custom JSON:API Pagination

📖 2 minutes read

When you’re building a search API with Laravel Scout and want to follow the JSON:API specification for pagination, you might run into a compatibility problem: packages like spatie/laravel-json-api-paginate don’t work with Scout queries, and packages that do support Scout (like jackardios/scout-json-api-paginate) might not support your Laravel version.

The good news? You can add this functionality yourself with a simple Scout macro.

The Problem

JSON:API uses a specific pagination format:

GET /api/reports?q=sales&page[number]=2&page[size]=20

But Scout’s built-in paginate() method expects Laravel’s standard pagination parameters. You need a bridge between these two formats.

The Solution

Add a macro to Scout’s Builder class in your AppServiceProvider:

// app/Providers/AppServiceProvider.php
use Laravel\Scout\Builder as ScoutBuilder;

public function boot()
{
    ScoutBuilder::macro('jsonPaginate', function ($maxResults = null, $defaultSize = null) {
        $maxResults = $maxResults ?? 30;
        $defaultSize = $defaultSize ?? 15;
        $numberParam = config('json-api-paginate.number_parameter', 'page[number]');
        $sizeParam = config('json-api-paginate.size_parameter', 'page[size]');
        
        $size = (int) request()->input($sizeParam, $defaultSize);
        $size = min($size, $maxResults);
        
        $number = (int) request()->input($numberParam, 1);
        
        return $this->paginate($size, 'page', $number);
    });

How to Use It

Now you can use jsonPaginate() on any Scout search query:

// In your controller
public function search(Request $request)
{
    $query = $request->input('q');
    
    $results = Report::search($query)
        ->query(fn ($builder) => $builder->where('active', true))
        ->jsonPaginate();
    
    return $results;
}

Your API will now accept JSON:API pagination parameters:

GET /api/reports?q=sales&page[number]=2&page[size]=20

Why This Works

The macro:

  1. Reads the JSON:API-style page[number] and page[size] parameters
  2. Enforces a max results limit (prevents clients from requesting too many results)
  3. Converts these to Scout’s expected format: paginate($perPage, $pageName, $page)
  4. Returns a standard Laravel paginator that works with Scout

You get JSON:API-compliant pagination without adding a whole package or creating a custom service provider.

Configuration

If you’re using spatie/laravel-json-api-paginate for your Eloquent queries, this macro will automatically use the same configuration keys from config/json-api-paginate.php. If not, it defaults to page[number] and page[size].

Tip: This pattern works for any Laravel class you want to extend. Macros are a lightweight way to add functionality without modifying vendor code or creating inheritance hierarchies.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *