Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Donny5300's avatar

JSON API ORG vs. Morph relationships

I've been watching the series from @jwmcpeak about mastering APIs (https://laracasts.com/series/laravel-api-master-class). Still though, I have a question about it.

He is referring to the JSON API.org which I keep now in my application, but what abouth Morphs? Im curious how you should handle those. The way how I see it, is that a Morph table is nothing more than a "class" which will be extended by another "class". For example:

urls table

  • id
  • url
  • morphTo a resource (Product/Brand/Category)
  • created_at
  • updated_at

products table

  • title
  • content

When rendering a resource, those 2 tables could be combined to 1 resource, like:

class ProductResource
{
    public function toArray()
    {
        return [
            'data' => [
                'attributes' => [
                    'id' => $this->resource->morph->id, // The product ID
                    'title' => $this->resource->morph->title,
                    'url' => $this->resource->url,
                    'content' => $this->resource->morph->content,
                ]
            ]
        ];
    }
}

Am I correct or am I completely out of my mind and bringing myself in problems later in the application?

0 likes
2 replies
LaryAI's avatar
Level 58

When dealing with polymorphic relationships in Laravel, especially when you want to expose them through a JSON API, it's important to understand how to properly structure your resources and relationships. The JSON:API specification provides a standardized way to represent resources and their relationships, which can be quite useful when dealing with polymorphic relationships.

In your case, you have a urls table that uses a polymorphic relationship to associate with different types of resources like Product, Brand, or Category. Here's how you can handle this in a JSON API-compliant way:

  1. Define the Polymorphic Relationship in Models:

    First, ensure that your models are set up correctly with the polymorphic relationship. For example, in your Url model, you would define the morphTo relationship:

    class Url extends Model
    {
        public function resourceable()
        {
            return $this->morphTo();
        }
    }
    

    And in your Product model (and similarly for Brand and Category), you would define the inverse relationship:

    class Product extends Model
    {
        public function urls()
        {
            return $this->morphMany(Url::class, 'resourceable');
        }
    }
    
  2. Create a Resource Class:

    When creating a resource class for your API, you should include the polymorphic relationship. Here's an example of how you might structure your ProductResource:

    use Illuminate\Http\Resources\Json\JsonResource;
    
    class ProductResource extends JsonResource
    {
        public function toArray($request)
        {
            return [
                'type' => 'products',
                'id' => (string) $this->id,
                'attributes' => [
                    'title' => $this->title,
                    'content' => $this->content,
                ],
                'relationships' => [
                    'urls' => [
                        'data' => $this->urls->map(function ($url) {
                            return [
                                'type' => 'urls',
                                'id' => (string) $url->id,
                                'attributes' => [
                                    'url' => $url->url,
                                ],
                            ];
                        }),
                    ],
                ],
            ];
        }
    }
    
  3. Handle the JSON:API Structure:

    Ensure that your API responses conform to the JSON:API specification. This means including type, id, attributes, and relationships in your resource representation.

  4. Consider Using a Package:

    If you want to fully adhere to the JSON:API specification, consider using a package like laravel-json-api or spatie/laravel-json-api-paginate which can help manage the complexities of the JSON:API format.

By structuring your resources and relationships in this way, you can effectively manage polymorphic relationships in a JSON API-compliant manner. This approach will help you avoid potential issues and ensure that your API is both flexible and maintainable.

jwmcpeak's avatar

@Donny5300

TIL there is a morphTo() method.

The way I see it, you need to bring the related data into the JSON structure when rendering the resource. morphTo() appears to be a clean way to do that. I don't think you're out of your mind.

Please or to participate in this conversation.