Challenge 2: Nest a Resource With whenLoaded() — Possible Solution ==================================================================== // app/Http/Resources/PublisherResource.php namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class PublisherResource extends JsonResource { public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, ]; } } // app/Http/Resources/BookResource.php — extended namespace App\Http\Resources; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class BookResource extends JsonResource { public function toArray(Request $request): array { return [ 'id' => $this->id, 'title' => $this->title, 'price' => $this->price, 'publisher' => new PublisherResource($this->whenLoaded('publisher')), ]; } } // --- Demonstrating the difference --- // app/Http/Controllers/BookController.php use App\Http\Resources\BookResource; use App\Models\Book; public function indexWithoutEagerLoad() { return BookResource::collection(Book::all()); } public function indexWithEagerLoad() { return BookResource::collection(Book::with('publisher')->get()); } RESULTING OUTPUT DIFFERENCE ------------------------------- indexWithoutEagerLoad() — publisher relationship NOT loaded: { "data": [ { "id": 1, "title": "Dune", "price": "12.99" } ] } // Notice "publisher" is entirely ABSENT from the JSON — not null, // just omitted, because whenLoaded('publisher') detected the // relationship was never loaded and skipped including the key at all. indexWithEagerLoad() — publisher relationship eager-loaded first: { "data": [ { "id": 1, "title": "Dune", "price": "12.99", "publisher": { "id": 3, "name": "Ace Books" } } ] } // "publisher" now appears, nested as a full PublisherResource object. WHY THIS WORKS -------------- - new PublisherResource($this->whenLoaded('publisher')) does two things at once: whenLoaded('publisher') either returns the loaded Publisher model (if with('publisher') ran upstream) or a special "missing value" marker (if it wasn't loaded) — wrapping that in PublisherResource means the whole key gets omitted from the final JSON when the value is missing, rather than crashing or emitting "publisher": null. - Critically, whenLoaded() NEVER triggers a fresh database query itself — it only checks whether the relationship happens to already be loaded in memory. This is exactly what makes it safe against the N+1 trap: using $this->publisher directly (without whenLoaded) would trigger a real lazy-load query if the relationship wasn't eager loaded, silently reintroducing N+1 for every book in the collection. - This gives API consumers of the SAME BookResource class two different (but both correct) response shapes depending entirely on what the controller chose to eager load — a deliberate, controllable trade-off between response payload size and query efficiency.