Hello! Welcome back to our module on API Development.
In our last lesson, you learned how to use individual API Resource classes to transform a single Eloquent model into a clean, standardized JSON response. This gave you granular control over the "shape" of your API data, a crucial skill for building robust APIs.
However, APIs rarely deal with single items. More often, you'll be returning lists of data—search results, a catalog of products, or a feed of recent articles. Simply looping and applying a single resource isn't enough, especially when pagination is involved.
Today, we'll build on your knowledge to handle these scenarios. The learning outcome is to use Resource Collections to format paginated and grouped data. We will explore how to apply your resource transformations to entire collections of models and how to correctly structure the JSON response to include vital pagination metadata.
Transforming Collections: The collection Method
Let's start with a simple collection of models, like all users from a specific department. In the last lesson, you created a UserResource to transform a single user. How do you apply that same transformation to a collection of users?
You don't need to manually loop through them. Instead, you can use the static collection method on your resource class. It accepts a collection of models (or a paginator instance, which we'll see next) and returns an object that knows how to transform each item.
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/users', function () {
// Get a simple collection of all users
$users = User::all();
// Apply the UserResource to the entire collection
return UserResource::collection($users);
});
This code takes all user models, applies the toArray logic from UserResource to each one, and wraps the result in a data key.
The following video provides a great practical example of this.
[02/10] Laravel Travel API: Public Endpoint with Pagination and Tests
The video from Laravel Daily demonstrates how to refactor a controller to use a resource collection, making the code cleaner and the response standardized.
Watch from 06:03 to 07:56. Notice how the controller is changed to return TravelResource::collection($travels). The video also points out the automatic data wrapper that Laravel adds, which is a key feature of resource collections.
Handling Paginated Data
Pagination is essential for performance and user experience when dealing with large datasets. When you use Laravel's paginate() method, you get back a special paginator object that contains not only the items for the current page but also metadata like the total number of items, the last page, and links to the next and previous pages.
API Resources integrate seamlessly with this. You simply pass the paginator instance to the collection method.
use App\Http\Resources\UserResource;
use App\Models\User;
Route::get('/users', function () {
// Get a paginated collection of users
$users = User::paginate(15);
// Pass the paginator instance to the collection method
return UserResource::collection($users);
});
Laravel is smart enough to detect that it's a paginated result and will automatically structure the JSON response to include the data and the pagination metadata.
The following article provides a clear, detailed breakdown of what this final JSON looks like.
A Guide to Pagination in Laravel - Using API Resources
This article from Laravel News has an excellent section on combining API Resources with pagination. It clearly shows the controller code and explains the resulting JSON structure.
Read the section titled 'Using API Resources with Pagination'. Pay close attention to the final JSON response. Notice how the user data is in the data key, and all the pagination info (current_page, total, etc.) is nested within links and meta keys.
As the article demonstrates, your response will have a top-level data key containing the array of transformed resources, and sibling links and meta keys containing all the pagination information.
{
"data": [
{ "id": 1, "name": "Andy Runolfsson", "email": "..." },
{ "id": 2, "name": "Rafael Cummings", "email": "..." }
],
"links": {
"first": "http://example.com/users?page=1",
"last": "http://example.com/users?page=4",
"prev": null,
"next": "http://example.com/users?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 4,
"path": "http://example.com/users",
"per_page": 15,
"to": 15,
"total": 50
}
}
This standardized structure is invaluable for frontend clients, as they can reliably find the data and the pagination controls in the same place for any paginated endpoint in your API.
The official documentation also confirms this behavior. Note how it states that paginated responses are always wrapped, even if you try to disable wrapping globally, to ensure the meta and links keys have a place to live.
Eloquent: API Resources - Data Wrapping and Pagination
Let's review the official Laravel documentation for the final word on how pagination and data wrapping interact.
Read the sections 'Data Wrapping and Pagination' and 'Pagination'. This reinforces the concept that the data, links, and meta structure is a deliberate and consistent feature of paginated resource collections.
Dedicated Resource Collection Classes
So far, we've used the static collection() method. This is great for most cases. However, what if you want to add custom metadata to the entire collection response? For example, what if you wanted to add a timestamp for when the collection was generated, or some summary statistics?
For this, you need a dedicated Resource Collection class. You can generate one with the --collection flag or by including Collection in the name.
php artisan make:resource UserCollection
This creates a class that extends ResourceCollection. Inside this class, you can override the toArray method to customize the entire top-level response.
Let's watch a video that demonstrates both creating a dedicated collection and adding metadata to it.
Laravel Advanced - Eloquent Api Resource - Complete Explanation
This video from Laratips shows you how to create a dedicated resource collection and, more importantly, why you would do so—to add custom top-level metadata.
First, watch from 05:37 to 06:36 to see how a UserResourceCollection is created. Notice the convention: Laravel assumes UserResourceCollection will use UserResource for each item. \nThen, watch from 32:02 to 33:29. This part shows how to add custom metadata (like a meta key) to the collection response, both from the controller and from within the collection class itself.
As you saw, a dedicated collection class gives you a hook to structure the entire response.
Here’s how you would use it to add a custom meta key:
-
Generate the class:
php artisan make:resource PostCollection -
Modify its
toArraymethod:// app/Http/Resources/PostCollection.php use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\ResourceCollection; class PostCollection extends ResourceCollection { public function toArray(Request $request): array { return [ 'data' => $this->collection, // This is the collection of transformed PostResource instances 'meta' => [ 'source' => 'My Awesome Blog API', ], 'links' => [ 'self' => url()->current(), ], ]; } } -
Use it in your controller:
// In your controller use App\Http\Resources\PostCollection; use App\Models\Post; public function index() { $posts = Post::paginate(); // Instantiate your new collection class return new PostCollection($posts); }
This approach is perfect for "grouped data" scenarios where you need to return a list of items along with summary information or other metadata relevant to the group as a whole.
Conclusion
You have now mastered the techniques for presenting collections of data through your Laravel API. By combining what you learned today with the previous lesson on single resources, you have a complete toolkit for shaping your JSON responses.
Key Takeaways:
- For simple collections, use the static
Resource::collection($models)method to apply a transformation to each item. - When working with paginated results, pass the paginator object directly to
Resource::collection(). Laravel will automatically include thedata,links, andmetakeys in the JSON response. - For more complex scenarios where you need to add custom metadata to the entire collection response, create a dedicated Resource Collection class (e.g.,
UserCollection) and customize itstoArraymethod. - This structured approach ensures your API is consistent, predictable, and easy for client applications to consume.
Up Next:
In the next lesson, we will focus on conditionally including attributes and relationships in API resources. We will expand on the conditional logic you've already seen and explore advanced techniques for building dynamic and context-aware API responses that can adapt to different permissions and data states.