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 useResource
inherited object. - Collection resource: If you want to return a collection like
/users
or/questions
then you will have to returnResourceCollection
inherited instance. You can useMyResource::collection
but it will not be customizable so far I have read.
php artisan make:resource UserResource
will createUserResource
file inside theApp\Http\Resources
that extendsIlluminate\Http\Resources\Json\Resource
class.php artisan make:resource UserCollection
will createUserCollection
class inside theApp\Http\Resources
directory. This extends theIlluminate\Http\Resources\Json\ResourceCollection
. This is also an extension ofResource
class.php artisan make:resource ArticleResource --collection
will createArticleResource
class inside theApp\Http\Response
directory. 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\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 thePaginatedResourceResponse
‘stoResponse
method or the parent’stoResponse
method. ThePaginatedResourceResponse
‘stoResponse
then 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 theResourceResponse
class fromResource::toResponse
method. And finally thetoResponse
inside theResourceResponse
resolves 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 thequestions
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$additional
values inside your class or pass those values to your class usingwith
andadditional
method. - If you want to customize your response, then you’ll have to override the
withResponse
method. This method accepts$request
and$response
parameters. 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.
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.