Laravel multiple API Resources for same model

We already know how Laravel API resources work. If you don’t know how to create and use laravel API resources you can find it here ( Laravel API Resources Documentaion ). One resource or resource collection is bind to a single model (resource class and model class have same name). Resource class identifies the model class by their name. But sometimes, we may need to return different type of data collection from the same model for developing purpose. For example, let’s say, from Employee table, sometimes we need only id and name & sometimes we need id, name, phone, address etc. In this case, we need to create different resource classes for the same model. But as we say, one model is bind to a single resource. And you can’t create multiple resources with same class name. Laravel won’t allow it normally.
So how can we achieve that !!!
Well, I have found two ways to achieve that.
First one is, by creating resource class with the same model name in different folder
php artisan make:resource Employeephp artisan make:resource Another/Employee
First command will create resource file Employee.php, in app\Http\Resources directory. And the second one will create, Employee.php in app\Http\Resources\Another directory. But this is a very poor approach. This approach should not be followed.
Second approach is, create resources as much as necessary. Every resources extends JsonResource. Now, whichever model we want to bind with a resource, we can bind that using constructor.
class EmployeeInfo extends JsonResource
{
function __construct(Employee $model)
{
parent::__construct($model);
}
// ...
}Here, I am going to explain this with the following example.
Example
Say, we have two models. Employee and Gender. The relation between these two models is,
<?php
namespace App\Models\Employee;
...
class Employee extends Model
{
...
function gender(){
return $this->belongsTo('App\Models\Gender', 'gender_id', 'id');
}
}Migration file for genders table
class CreateGendersTable extends Migration
{
public function up()
{
Schema::create('genders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
}
...
}Migration file for employees table
class CreateEmployeesTable extends Migration
{
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->unsignedBigInteger('gender_id');
$table->timestamps();
});
}
...
}Now, I will create two resources.
First resource,
This resource bind employee model normally as resource model binding. It will return only id and name of an employee.
class Employee extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}Second resource,
It will return id, name and gender name of an employee. Here, the Employee model object is passed through the constructor.
class EmployeeGenderInfo extends JsonResource
{
function __construct(Employee $model)
{
parent::__construct($model);
} public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'gender_name' => $this->gender->name, ];
}
}
Now the $this keyword refers the Employee model. So, now this resource also can use Employee model data to return.
One more thing
We need to define the model through constructor only in the resource class. if we have a resource collection for the same resource, we don’t need to define that model again. We can write the resource collection normally like other resource collection. Like, from the given example, for the resource collection of the second resource, simply write
class EmployeeGenderInfo extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'meta' => ['api-version' => '1.0']
];
}
}This is my first blog here. Please, forgive me if anything is wrong and you also can share your opinion. So that, I can correct my mistakes.
Thank you.
