Optimizing API Responses: Conditional Relationship Counts in Laravel Resources
When building APIs with Laravel, it's often necessary to include the count of related models in your responses. However, including these counts can be costly if not done efficiently. Laravel's API Resources provide elegant methods to conditionally include relationship counts, allowing you to optimize your API responses. Let's explore how to leverage these features effectively.
Understanding Conditional Relationship Counts
Laravel allows you to conditionally include relationship counts in your API responses using the whenCounted
method. This method only includes the count if it has been explicitly loaded on the model, preventing unnecessary database queries.
Basic Usage of whenCounted
Here's a simple example of how to use whenCounted
:
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts_count' => $this->whenCounted('posts'),
'comments_count' => $this->whenCounted('comments'),
];
}
}
In this example, posts_count
and comments_count
will only be included in the response if they've been loaded using withCount()
on the query.
Loading Counts in Controllers
To make use of whenCounted
, you need to load the counts in your controller:
public function index()
{
$users = User::withCount(['posts', 'comments'])->get();
return UserResource::collection($users);
}
Advanced Usage with Aggregates
Laravel also provides methods for other types of aggregates:
• whenAggregated
: For general aggregate functions
• whenSummed
: For sum aggregates
• whenAvg
: For average aggregates
• whenMin
: For minimum value aggregates
• whenMax
: For maximum value aggregates
Here's an example using various aggregates:
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'posts_count' => $this->whenCounted('posts'),
'comments_count' => $this->whenCounted('comments'),
'total_post_views' => $this->whenSummed('posts', 'views'),
'average_post_rating' => $this->whenAvg('posts', 'rating'),
'latest_post_date' => $this->whenMax('posts', 'created_at'),
];
}
}
Practical Example: Blog API
Let's consider a more comprehensive example for a blog API:
class PostResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'content' => $this->content,
'author' => new UserResource($this->whenLoaded('author')),
'comments_count' => $this->whenCounted('comments'),
'likes_count' => $this->whenCounted('likes'),
'average_rating' => $this->whenAvg('ratings', 'score'),
'tags' => TagResource::collection($this->whenLoaded('tags')),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
In your controller:
public function index(Request $request)
{
$posts = Post::query()
->with(['author', 'tags'])
->withCount(['comments', 'likes'])
->withAvg('ratings', 'score');
if ($request->include_content) {
$posts->addSelect('content');
}
return PostResource::collection($posts->paginate());
}
By leveraging Laravel's conditional relationship counts in API Resources, you can create more efficient and flexible API responses. This approach allows you to include valuable aggregate data in your API without compromising performance, leading to faster and more scalable applications.
If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!