Laravel API Resources & Collections with Examples

API Resources & Collections
Spread the love
  •  
  •  
  •  
  •  
  •  
  •  
  •  

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.

API Resources & Collections
API Resources & Collections

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:

API Resources & Collections

I will get the same product data.

API Resources & Collections

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:

API Resources & Collections

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:

API Resources & Collections

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:

API Resources & Collections

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:

API Resources & Collections

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.

Read More: Laravel View Composers and Custom Blade Directives


Spread the love
  •  
  •  
  •  
  •  
  •  
  •  
  •  

About Anisur Rahman Shahin

Hello. My name is Shahin. I'm a tech enthusiast guy. Personally, I’m Optimistic and always in hurry kinda person. I'm a freelance web developer. I am working at Zakir Soft as Laravel Developer. My Portfolio website: https://devshahin.com/

View all posts by Anisur Rahman Shahin →

Leave a Reply

Your email address will not be published. Required fields are marked *