Considerations when eager loading resource collections

Check out a subtle bug that avoided notice for a while, and how tests eventually helped us.

Joel Clermont
Joel Clermont
2023-11-20

In one of our projects, we use a pattern to consolidate eager loading logic within our ResourceCollection classes. This way we don't have to repeat the eager loading logic in all the places we use a collection.

Here's what it looked like:

// inside the PositionCollection class
public static function applyEagerLoad(Builder $resource): void
{
    $resource->with([
        'locations',
        'managers',
        'applicants' => function (HasMany $query) {
            $query->where('applicant_status_id', ApplicantStatus::AWARDED);
        },
    ]);
}

// in a controller, we can use this method and not duplicate the eager loading logic
PositionCollection::applyEagerLoad($query);

But notice that in this example, the applicants relationship is also constrained to a particular applicant status. Inside the resource, we can then assume we're always working with awarded applicants.

What was overlooked is that eager loading only happens in the index controller action, where we're returning a collection of resources. In the show controller action there is no eager loading, since an individual resource doesn't need it.

So inside our resource, when we use this applicants relationship, we actually could not rely on it to always be constrained. This led to a bug where the resource field values could be different, depending on whether you were looking at a single resource or a collection of resources.

The index controller action, which had more complexity like filtering, sorting, and pagination, had excellent test coverage. But the show controller action tests were marked as todo. We sometimes do this to meet a project deadline, but we always make sure we come back and finish the tests later.

In this case, while we were dutifully back-filling those todo tests, we discovered this bug. It was subtle, and it didn't cause any problems for users, but it was a good reminder of the value of tests.

Here to help,

Joel

P.S. Resources are a great Laravel feature when building APIs. If you want to go deep on this topic, our buddy Ash has an excellent book.

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼

Level up your Laravel skills!

Each 2-minute email has real-world advice you can use.