Laravel API resources
When building an api, many developers will use a transformation layer that sits between the models and the JSON responses that are returned to the application’s users.
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.
Let’s start by generating a resource using the
make:resource Artisan command:
php artisan make:resource VehicleResource
Let’s take a look at what was created:
We have a new class which 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.
Let’s set up our vehicle model and try this out!
I will make a model, migration and controller to represent the Vehicle object, and a migration file with a small number of fields:
I’ll then add the resource routing to route to our VehicleController:
Now from the
show() method in my Vehicle controller I can return the vehicle object directly:
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/vehicle/1:
However now if I try returning the same data using my VehicleResource:
I will get the same vehicle data wrapped in a JSON object called 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 of
data, you may define a
$wrap attribute on the resource class:
Which gives the following output:
You can also disable the wrap data wrap completely by invoking the
withoutWrapping 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 on 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 a 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 vehicle 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
In this case I changed the ‘model’ name to ‘model_name’ and removed any date fields to stop those from being returned.
You can handle relationships really nicely with API resources — it is one of the big advantages of using a transformation layer.
I’ve added a simple one to many relationship with a Company to show this:
As you can see this loads the company data too:
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.
To load a collection of objects you can use the static collection method:
This will load data as an array of vehicles:
Or you can create a new resource collection. To do this run the following command:
php artisan make:resource VehicleCollection
You should see a new file now in
As you can see this class extends
ResourceCollection, rather than
JsonCollection as before.
Now if we replace the line in the
with our new
return new VehicleCollection($vehicles);
We can also paginate like this, passign pagination directly into the collection.
preserveQuery will add any url parameters to the ‘links’ section in the pagination response:
We should see exactly the same response — but now we have much more control over how the data is returned. Again — as with the
JsonRespource — we can modify the toArray method to get the response we want.
If you were unfamiliar I hope this has showed you some use cases for using API Resources in Laravel. You can learn more about this topic in the Official Documentation. I hope it helps you in your projects!