I have been working on RESTful APIs in laravel alot lately and on my last two projects I have alot of relationships that needed to be loaded on different pages (on the frontend) ,so I thought about different ways to load them:
-
First I thought I about returning all of the relationships on show API request /api/products/{product} so this will return the product and its relationships array or objects, but this sometimes will return unwanted relationships on some pages, which can be bad for performance since it will be loading things we don’t need
-
Second option I thought about making different API endpoints for each relationships:
- Main details will be on
/api/products/{product}
- Different API for each relationships like loading product categories will be on
/api/products/{product}/categories
But this will cause requesting many endpoints if the page is showing many relationships
-
So the last option which is now I am using is making a request parameter in which I can pass the relationships I want to load like this /api/products/{product}?include[]=categories so now I can use one request to only load the relationships I need on my page, and till now I think this is a good idea.
This is how I am doing this, I made this trait which I can use on the models I want to dynamically load its relationships by overriding the with and withCount arrays on the models.
So I want some comments and reviews about the dynamic relationships loading way,
Because I did some search about it and didn’t find any solutions for this.
I know this is similar to graphQL, but can this idea still be valid on RESTful APIs.
And Thank you very much in advance.
<?php
namespace App\Traits;
trait LoadRelations
{
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
if (request('include_count')) {
$includedRelationsCount = request('include_count');
array_map(function ($relation) {
$this->checkRelationsCountExists($relation);
}, $includedRelationsCount);
}
if (request('include')) {
$includedRelations = request('include');
array_map(function ($relation) {
$this->checkRelationsExists($relation);
}, $includedRelations);
}
}
private function loadIfLoadableRelationCount($relationCount)
{
if (in_array($relationCount, $this->loadableRelationsCount)) {
$this->withCount[] = $relationCount;
}
}
private function loadIfLoadableRelation($relation)
{
if (in_array($relation, $this->loadableRelations)) {
$this->with[] = $relation;
}
}
private function checkRelationsExists($relation)
{
if (method_exists($this, $relation)) {
$this->loadIfLoadableRelation($relation);
}
if (method_exists($this, camel_case($relation))) {
$this->loadIfLoadableRelation(camel_case($relation));
}
}
private function checkRelationsCountExists($relation)
{
if (method_exists($this, $relation)) {
$this->loadIfLoadableRelationCount($relation);
}
if (method_exists($this, camel_case($relation))) {
$this->loadIfLoadableRelationCount(camel_case($relation));
}
}
}