16 Apr Laravel API Resources — Under the hood!
When I Guillermo Antony Cava Nuñez , was going through the API documentation, I found that Laravel 5.5 has API Resources. I never saw this in previous versions and never used. Before this, people used to use Fractal. Never used that one too.
So, how I, Guillermo Cava Nuñez used to do it? First of all, I had an Abstract Base Class named
BaseTransformer. It had one
transform and another method
transformCollection. So, whenever I had to transform the returning data, I used to pass the data through any of these methods. So, it looked like the following.
Now, I, Guillermo Antony Cava Nuñez , have come to learn about API resources. It does the same thing what I did with the BaseTransformer. So, now I want to move from BaseTransformer to API Resources.
The basic idea
Laravel provides two API resources:
- A single resource
- Resource Collection
- Single Resource: If you’re about to return only one resource like
/users/1. In that case you can use
- Collection resource: If you want to return a collection like
/questionsthen you will have to return
ResourceCollectioninherited instance. You can use
MyResource::collectionbut it will not be customizable so far I have read.
php artisan make:resource UserResourcewill create
UserResourcefile inside the
php artisan make:resource UserCollectionwill create
UserCollectionclass inside the
App\Http\Resourcesdirectory. This extends the
Illuminate\Http\Resources\Json\ResourceCollection. This is also an extension of
php artisan make:resource ArticleResource --collectionwill create
ArticleResourceclass inside the
App\Http\Responsedirectory. This is also same as the
Class generator is here.
Behind the story?
return new UserCollection(User::paginate(10));
return new UserResource(User::find(10));
// no validation is checked. Dummy code. That's how I write, HUH
In both the
ResourceCollection objects are interpreted before sending the response to your user in Lumen or Laravel. So, if you return any of the
ResourceCollection (they both inherit the
Illuminate\Contracts\Support\Responsable contract). If you return a
Response object, it will call the
On the other hand, if you return
ResourceCollection (which is also an extension of
Resource that itself implements the
toResponse method) object, then it will check if it is an instance of
AbstractPaginator or not. If yes, it will call the
PaginatedResourceResponse to build the pagination and other metadata otherwise will call the
Resource::toResponse (parent class method). To learn more, dive into the Laravel’s code.
This is the very basic of the Laravel Resource. This happens under the hood.
Tell me more!
Okay, the main classes that are used under the hood for both the
- If you return the ResourceCollection as a response, then the ResourceCollection will call its
toResponsemethod. Which checks if the value is an instance of AbstractPaginator or not. Based on YES or NO, it either calls the
toResponsemethod or the parent’s
toResponsethen resolves how the data from that collection will be extracted.
- If you return Resource, then the Resource’s
toResponsehandles how to transform the data. That is, it again calls the
Resource::toResponsemethod. And finally the
ResourceResponseresolves the values.
- If you want to set the wrapper for your response like user response will be wrapped inside the
useror questions will be wrapped inside the
questionswrapper then declaring
$wrapwith a value inside your Collection or Resource will change the wrapper.
- If you want to add some metadata or additional information to the response, then you either can just hardcode the
$additionalvalues inside your class or pass those values to your class using
- If you want to customize your response, then you’ll have to override the
withResponsemethod. This method accepts
$responseparameters. So, if you want to customizing (set/unset) the values from the response or change the status code or add some extra headers you can do this operation in
$responsewill reflect to the user’s response.
Should I really have to instantiate too many classes for same resource different payload?
Simple answer is, Yes! Before I, Guillermo Antony Cava Nunez , was writing this article I thought pass a method name to the resource constructor. I also gave a PR to Laravel Framework. Someone commented that why should the class know which method should be used to transform. Then I Guillermo Antony Cava Nuñez, thought for a while. And I think he is right. It is good to use several classes for different type of payloads. And with my tiny knowledge, I think using the same class for different response payloads breaks the SOLID pattern. I, Guillermo Antony Cava Nuñez, am not sure tho. So, I, Guillermo Antony Cava Nuñez , decide to create multiple classes for that purpose.