API Resources & Collections in Laravel. When building an API, many developers will use a transformation layer. That sits between the models and the JSON responses which are returned to the consumers.
As a Laravel developer you may be familiar with packages like this https://fractal.thephpleague.com/transformers/, however, Laravel now has API resources built-in since version 5.5 and over time many people have switched over.

Why even have a transformation layer?
Of course, you can convert models or collections to JSON using their toJson method, however, a transformer will give you more control over the JSON serialization of your models and their relationships. For example, you may want to always or sometimes include certain relationships in the JSON representation of your models. You have control over the naming of JSON properties as they are returned to the user, and you may wish to display certain attributes for a subset of users and not others. This is all made easier by having a transformation layer.
Generating Resources
To generate a resource class, you may use the make:resource
Artisan command. By default, resources will be placed in the app/Http/Resources
directory of your application. Which extends the Illuminate\Http\Resources\Json\JsonResource
class.
I will make a class according to product resources. Let’s assume we have a product model and migration file. In the product table, we have a couple of columns. Let’s make a resources class.
php artisan make:resource ProductResource
Look at this class.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}
We have a new class that extends the JsonResource class and a toArray method which simply delegates to the toArray
method on the eloquent model — we can modify this method to convert to JSON when sending the response. Notice that we can access model properties directly from the $this
variable. This is because a resource class will automatically proxy property and method access down to the underlying model for convenient access.
I’ll then add the resource routing to route to our VehicleController:
Route::resource(‘product’, ProductController::class);
Now from the show()
the method in my Vehicle controller I can return the vehicle object directly:https://medium.com/media/b80974fb8ef716044da3f00ac08a2877
I’ll run php artisan serve
so that I can view my requests and responses. I’ll also make some dummy data in my database.
In this case, I get the following response when I navigate to http://localhost:8000/api/product/1:

I will get the same product data.

By default, your outermost resource is wrapped in a data
key when the resource response is converted to JSON.
If you would like to use a custom key instead, you may define an $wrap
attribute on the resource class.
Which gives the following output:

You can also disable the wrap data wrap completely by invoking the method on the base Illuminate\Http\Resources\Json\JsonResource
class. Typically, you should call this method from your AppServiceProvider
or another service provider that is loaded on every request to your application.
Note: You can disable all resources by using JsonResource::withoutWrapping();
which will disable wrapping for all your resources that inherit from the JsonResource class.
Returning more data
Let’s say we wanted to return status with the response. We can return anything we want by using the with()
method in the resource class.
This now returns sibling data alongside our product data — which could be whatever you like:

Returning less data
We may want to return some fields but not others or change the names of the fields for public consumption. In that case, we can specify exactly what we do want to return by specifying the fields in the toArray()
method.
In this case, I have changed the ‘model’ name to ‘model_name’ and removed any data fields to stop those from being returned.
Loading relationships
You can handle relationships really nicely with API resources — it is one of the big advantages of using a transformation layer.
I’ve added simple one to many relationships with a Company to show this
As you can see this loads the company data too:

Conditional Attributes
You may want to conditionally load attributes, for example when a user has a certain role. You can use $this->when
method to perform a check based on your criteria. If you wanted to load the ‘company’ relationship conditionally you could use this:
‘company’ => $this->when(<your condition (boolean)>, $this->company),
You can also conditionally load the relationship based on if the relationship has already been loaded on the model:
‘company’ => $this->whenLoaded(‘company’),
The line above will not return a company in the response since the relationship was not loaded.
‘company’ => $this->whenLoaded(‘company’, $this->company),
This will load the company if it hasn’t been loaded already.
Loading Collections
To load a collection of objects you can use the static collection
This will load data as an array of products:

Or you can create a new resource collection. To do this run the following command:
php artisan make:resource ProductCollection
API Resources & Collections
You should see a new file now in App/Http/Resources/ProductCollection.
As you can see this class extends ResourceCollection
, rather than JsonCollection
as before.
Now if we replace the line in the ProductController
:
return ProductResource::collection(Product::get());
with our new Productollection
:
return new ProductCollection($products);
We can also paginate like this, passing pagination directly into the collection. preserveQuery
will add any URL parameters to the ‘links’ section in the pagination response.
return new ProductCollection(Product::paginate(2));
We should see exactly the same response — but now we have much more control over how the data is returned. Again — as with the JsonResource
— we can modify the toArray method to get the response we want.