API Resource — Laravel 10 Discovery Training

In this chapter we will discuss the API part of Laravel and we will see how to manage the serialization of our models in JSON. By default, when a model is returned directly in a controller, Laravel will convert it into an array and then into JSON by exposing all the attributes of the model. In a real case we want to be able to select the fields to expose via our API and this is where the Resource system comes in.

As usual, to create this type of class, we will go through an artisan order.

php artisan make:resource PostResource

Then we can use this class in the controller when we want to return information from a model.

function show (Post $post) {
    return new PostResource($post);
}

And also use the static method in case of a collection

function index () {
    return PostResource::collection(Post::limit(5)->get());  
}

In the resource it is possible to define the fields to be returned using the method toArray().

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->name,
            'slug' => $this->email,
            'published_at' => $this->published_at
        ];
    }
}

Note that the model property can be accessed using the variable $this directly. The Resource class will automatically proxy and use the model’s properties and methods. If you are not comfortable with this “magic” you can also access the property $resource which will contain the current model.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/**
 * @property App\Models\Post $resource
 **/
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->resource->id,
            'title' => $this->resource->name,
            'slug' => $this->resource->email,
            'published_at' => $this->resource->published_at
        ];
    }
}

It is also possible to condition the presence of a property using various methods such as when().

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/**
 * @property App\Models\Post $resource
 **/
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->resource->id,
            'title' => $this->resource->name,
            'slug' => $this->resource->email,
            'published_at' => $this->resource->published_at,
            'created_at' => $this->when($request->user()->isAdmin(), $this->resource->created_at)
        ];
    }
}

You also have the possibility to include elements from a relation, and to include it only if the relation has been preloaded.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

/**
 * @property App\Models\Post $resource
 **/
class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->resource->id,
            'title' => $this->resource->name,
            'slug' => $this->resource->email,
            'tags' => TagResource::collection($this->whenLoaded('tags')),
            'published_at' => $this->resource->published_at,
        ];
    }
}

Collection

In addition to the classic resources, you can also generate resources that will be used to represent collections.

php artisan make:resource PostCollection
# si le nom de la classe ne termine pas par "Collection"
php artisan make:resource PostResource --collection

This class also has a method toArray() which allows you to specify the return. In this method you can use the property $collection to retrieve the item collection.

<?php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class PostCollection extends ResourceCollection
{

    public function toArray($request)
    {
        return [
            'data' => $this->collection,
            'meta' => [
                'base' => 'https://grafikart.fr/',
            ],
        ];
    }
}