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.