Including relationships in Laravel API resource response

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
# Including Relationships in Laravel API Resource Responses: Mastering Eager Loading As developers building robust APIs with Laravel, one of the most common challenges we face is transforming complex Eloquent relationships into clean, consumable JSON responses. When dealing with nested data, such as books and their associated ratings, the key lies not just in defining the relationships correctly, but crucially in *how* you load that data before transforming it into a resource. This post will walk you through the common pitfall of lazy loading in API scenarios and demonstrate the correct way to use Eloquent's eager loading mechanism (`with()`) to seamlessly include related data within your Laravel API resources. We will specifically address how to correctly display collections of relationships, as seen in your book store example. ## The Problem: The N+1 Query Trap You have defined a clear one-to-many relationship: a `Book` has many `Rating`s. When you use standard Eloquent fetching methods, if you iterate over books and then access their related ratings inside a loop, Laravel executes an extra query for *each* book to fetch its relationships. This is known as the N+1 query problem, which severely impacts API performance, especially with large datasets. In your scenario, when you fetch `Book::all()` or a single `$book`, by default, Eloquent only loads the parent model; it does not automatically load the related `ratings`. Consequently, when your `BookResource` attempts to access `$this->whenLoaded('ratings')`, it finds nothing, resulting in empty or missing data in your final response. ## The Solution: Eager Loading with `with()` The solution is to instruct Eloquent to fetch all necessary related data in a single, optimized query using **eager loading**. This is achieved by using the `with()` method on your Eloquent query builder. For your book store API, this means modifying how you retrieve the data before passing it to your resource. ### Step 1: Eager Loading in Route Definitions We need to modify the routes to explicitly load the `ratings` relationship whenever we request books. **Before (Inefficient):** ```php Route::get('/books', function() { return BookResource::collection(Book::all()); // Loads books, then N queries for ratings later }); Route::get('books/{book}', function(Book $book) { return new BookResource($book); // Loads book, then requires separate loading for ratings }); ``` **After (Efficient):** We modify the query to eagerly load the `ratings` relationship. This ensures that when the data is retrieved from the database, all necessary related records are fetched simultaneously. ```php Route::get('/books', function() { // Eager load the 'ratings' relationship $books = Book::with('ratings')->get(); return BookResource::collection($books); }); Route::get('books/{book}', function(Book $book) { // For a single resource, eager loading is often done via relationships // Ensure the model instance is loaded with relations if it wasn't already, // though route model binding handles the initial load. $book = Book::with('ratings')->findOrFail($book->id); return new BookResource($book); }); ``` By adding `->with('ratings')`, you instruct Eloquent to use a `LEFT JOIN` or separate optimized queries to fetch all books *and* their associated ratings in one efficient operation. This practice is fundamental to writing high-performance applications, aligning with Laravel's focus on clean and powerful data handling. ## Step 2: Ensuring the Resource Can Handle Nested Data Your `BookResource` is already set up correctly to handle nested resources using `RatingResource::collection($this->whenLoaded('ratings'))`. The crucial part is that this method *only* works if `$this->whenLoaded('ratings')` returns a collection of related models (which it will, once eager loading is applied). Your resource structure remains robust: ```php // In BookResource.php public function toArray($request) { return [ 'id' => $this->id, 'title' => $this->title, 'author' => $this->author, // This line now successfully iterates over the eagerly loaded 'ratings' collection 'ratings' => RatingResource::collection($this->whenLoaded('ratings')) ]; } ``` Notice that we renamed `'rating'` to `'ratings'` in the example above to reflect that it will contain a collection of ratings, which is standard practice when dealing with one-to-many relationships. This pattern allows you to nest related resources beautifully within your API output. ## Conclusion Mastering Eloquent relationships and Laravel Resources is about understanding data flow: **Load first, then transform.** By consistently applying eager loading (`with()`) in your route definitions, you eliminate the performance bottlenecks associated with lazy loading and ensure that your API responses are both accurate and lightning-fast. Always prioritize efficient data retrieval when building complex endpoints, adhering to best practices taught by the Laravel community.