Laravel Api Resources - Under The Hood!
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 used to do it? First of all, I had an Abstract Base Class named BaseTransformer. It had one abstract method 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, 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 Resource inherited object. - Collection resource: If you want to return a collection like
/usersor/questionsthen you will have to returnResourceCollectioninherited instance. You can useMyResource::collectionbut it will not be customizable so far I have read.
php artisan make:resource UserResourcewill createUserResource.phpfile inside theApp\Http\Resourcesthat extendsIlluminate\Http\Resources\Json\Resourceclass.php artisan make:resource UserCollectionwill createUserCollection.phpinside theApp\Http\Resourcesdirectory. This extends theIlluminate\Http\Resources\Json\ResourceCollection. This is also an extension of Resource class.php artisan make:resource ArticleResource --collectionwill createArticleResourceclass inside theApp\Http\Responsedirectory. This is also same as theUserCollection.
Class generator is here.
Behind the story?
web.php
Route::get('users', function(){
return new UserCollection(User::paginate(10));
});
Route::get('users/10', function(){
return new UserResource(User::find(10));
});
In both the Resource and ResourceCollection objects are interpreted before sending the response to your user in Lumen or Laravel. So, if you return any of the Resource or ResourceCollection (they both inherit the Illuminate\Contracts\Support\Responsable contract). If you return a Response object, it will call the Resource::toResponse method.
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 Resource or ResourceCollection are
- Illuminate\Http\Resources\Json\ResourceCollection
- Illuminate\Http\Resources\Json\Resource
- Illuminate\Http\Resources\Json\PaginatedResourceResponse
- Illuminate\Http\Resources\Json\ResourceResponse
-
If you return the ResourceCollection as a response, then the ResourceCollection will call its toResponse method. Which checks if the value is an instance of AbstractPaginator or not. Based on YES or NO, it either calls the PaginatedResourceResponse‘s toResponse method or the parent’s toResponse method.
The
PaginatedResourceResponse::toResponsethen resolves how the data from that collection will be extracted. -
If you return
Resource, then the Resource’s toResponse handles how to transform the data. That is, it again calls theResourceResponseclass fromResource::toResponsemethod. And finally thetoResponseinside theResourceResponseresolves the values.
Tweaks
- If you want to set the wrapper for your response like user response will be wrapped inside the user or questions will be wrapped inside the questions wrapper then declaring $wrap with 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 $with and $additionalvalues inside your class or pass those values to your class using with and additional method.
- If you want to customize your response, then you’ll have to override the withResponse method. This method accepts $request and $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 $response will reflect to the user’s response.