CODEX

Laravel API resources

How to use them effectively

Paul Reaney
CodeX
Published in
5 min readMar 5, 2021

--

Photo by MICHAEL WILSON on Unsplash

Introduction

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.

Application

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:

Route::resource(‘vehicle’, VehicleController::class);

Now from the show() method in my Vehicle controller I can return the vehicle object directly:

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/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 toArray() method:

In this case I changed the ‘model’ name to ‘model_name’ and removed any date 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 a simple one to many relationship 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 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 App/Http/Resources/VehicleCollection.php:

As you can see this class extends ResourceCollection, rather than JsonCollection as before.

Now if we replace the line in the VehicleController:

return VehicleResource::collection($vehicles);

with our new VehicleCollection:

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 JsonResource — we can modify the toArray method to get the response we want.

Summary

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!

--

--

Paul Reaney
CodeX
Writer for

I am a software developer and I like to write about interesting things I come across in my day to day.