Kritim Yantra
Apr 16, 2025
In this blog post, we'll explore how to use the Spatie Laravel-Query-Builder package in Laravel 12 to create powerful, filterable API endpoints with minimal code. This package simplifies complex query building while maintaining clean, readable syntax.
The Spatie Laravel-Query-Builder package provides an elegant way to:
?filter[name]=John
).?sort=name,-created_at
).?include=posts,comments
).?fields[users]=id,name
).It's perfect for building RESTful APIs with complex filtering requirements.
If you don’t have Laravel 12 installed:
composer create-project laravel/laravel query-builder-demo
cd query-builder-demo
composer require spatie/laravel-query-builder
php artisan make:model Post -mcr
Run migrations:
php artisan migrate
In your controller (PostController.php
):
use Spatie\QueryBuilder\QueryBuilder;
public function index()
{
$posts = QueryBuilder::for(Post::class)
->allowedFilters(['title', 'author'])
->get();
return response()->json($posts);
}
Now you can filter via URL:
/posts?filter[title]=Laravel&filter[author]=John
By default, filters use exact matching. For partial matches:
->allowedFilters(['title', AllowedFilter::partial('author')])
Now ?filter[author]=jo
matches "John".
use Spatie\QueryBuilder\AllowedFilter;
->allowedFilters([
AllowedFilter::callback('published_after', function ($query, $value) {
$query->where('published_at', '>=', $value);
})
])
Usage:
/posts?filter[published_after]=2024-01-01
Apply model scopes directly:
->allowedFilters([
AllowedFilter::scope('popular'),
])
In Post.php
:
public function scopePopular($query)
{
return $query->where('views', '>', 1000);
}
Usage:
/posts?filter[popular]=true
->allowedSorts(['title', 'created_at'])
Usage:
/posts?sort=title,-created_at // (Descending)
->allowedSorts([
AllowedSort::custom('length', new StringLengthSort()),
])
See official docs for custom sort classes.
->allowedIncludes(['author', 'comments'])
Usage:
/posts?include=author,comments
->allowedIncludes(['author.profile'])
Now ?include=author.profile
works.
$posts = QueryBuilder::for(Post::class)
->paginate();
URL:
/posts?page=2
->paginate(perPage: 15)
Or via request:
/posts?page=2&per_page=15
->allowedFields(['id', 'title'])
Usage:
/posts?fields[posts]=id,title
/posts?include=author&fields[author]=name
QueryBuilder::for(Post::class)
->defaultFilter('status', 'published')
return PostResource::collection($query->paginate());
allowedFilters()
carefully to avoid slow queries.The Spatie Laravel-Query-Builder package supercharges Laravel APIs by:
✅ Simplifying complex filtering with URL parameters.
✅ Reducing boilerplate code for sorting & relationships.
✅ Maintaining clean, readable syntax.
✅ Working seamlessly with pagination & resources.
Perfect for admin panels, public APIs, or data-heavy applications.
Happy query building! 🚀
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google