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 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, 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 useResourceinherited 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 createUserResourcefile inside theApp\Http\Resourcesthat extendsIlluminate\Http\Resources\Json\Resourceclass.php artisan make:resource UserCollectionwill createUserCollectionclass inside theApp\Http\Resourcesdirectory. This extends theIlluminate\Http\Resources\Json\ResourceCollection. This is also an extension ofResourceclass.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));
});
// no validation is checked. Dummy code. That's how I write, HUH
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\ResourceCollectionIlluminate\Http\Resources\Json\ResourceIlluminate\Http\Resources\Json\PaginatedResourceResponseIlluminate\Http\Resources\Json\ResourceResponse
- 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 thePaginatedResourceResponse‘stoResponsemethod or the parent’stoResponsemethod. ThePaginatedResourceResponse‘stoResponsethen 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 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
useror questions will be wrapped inside thequestionswrapper 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
$withand$additionalvalues inside your class or pass those values to your class usingwithandadditionalmethod. - If you want to customize your response, then you’ll have to override the
withResponsemethod. This method accepts$requestand$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.
