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 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:

  1. A single resource
  2. 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 /users or /questions then you will have to return ResourceCollection inherited instance. You can use MyResource::collection but it will not be customizable so far I have read.
  1. php artisan make:resource UserResource will create UserResource file inside the App\Http\Resources that extends Illuminate\Http\Resources\Json\Resource class.
  2. php artisan make:resource UserCollection will create UserCollectionclass inside the App\Http\Resources directory. This extends the Illuminate\Http\Resources\Json\ResourceCollection. This is also an extension of Resource class.
  3. php artisan make:resource ArticleResource --collection will create ArticleResource class inside the App\Http\Response directory. This is also same as the UserCollection.

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

  1. Illuminate\Http\Resources\Json\ResourceCollection
  2. Illuminate\Http\Resources\Json\Resource
  3. Illuminate\Http\Resources\Json\PaginatedResourceResponse
  4. 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‘s toResponse 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 the ResourceResponse class from Resource::toResponse method. And finally the toResponse inside the ResourceResponse resolves the values.

Tweaks

  1. 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.
  2. 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.
  3. 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.

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.