How to structure Laravel API resources folder properly

193 Views Asked by At

I wonder what are the best practices that the community have about the architecture of Laravel's Resources.

I started using it to avoid sending unnecessary data to certain routes of the API.

I structured it the way my API routes looks like, with specific namespaces corresponding to the routes.

However, doing this faced me to a conceptual problem which is that it forces me to duplicates a lot of Resources that often returns the same data.

For example, if I get a route users/user returning a Resources\Users\User UserResource that would return :

return [
            'id' => $this->id,
            'name' => $this->name,
            'firstname' => $this->firstname,
            'fullName' => $this->fullName(),
        ];

And then create another route named holiday/user, I would create the same resource under namespace Resources\Holiday\ or something like that.

Should I create some global folder for example Users in which I would have different representations of a User, and then pick them depending on my route's use case?

But doing this might involve that I sometimes got data I won't need.

I wonder what are the community's best practices on this subject?

2

There are 2 best solutions below

0
JulBeg On

What I like to do is organize my resources by model and route action. For example, for a User model, I have the following:

    Resources\User\UserIndexResource.php // Lists of users
    Resources\User\UserEditResource.php // Edits a user
    Resources\User\UserShowResource.php // Displays a user

If I need a specific resource for a relation like $holiday->user, I simply add it to the holiday resources:

    Resources\Holiday\HolidayUserResource.php

These organized resource files help me maintain a clear and structured approach to handling different model actions and relationships.

0
Hesam Rad On

This is what I came up with on an enterprise product. (And it works really well.)

I realized that there are only two cases in which I'm using my resource classes:

  1. Showing a list of that resource (A preview if you will)
  2. Showing all the necessary details of that resource.

In this case, I created 2 separate resource classes for every model.

For example, if I wanted to do this for my User model, I would create a Minor and a Major resource class under App\Http\Resources\User; so it would be like this:

- app
-- Http
--- Resources
---- User
----- Minor.php
----- Major.php

The Minor class is only used for cases that you need a few properties from the User class; and the Major class is used for the cases that you need all the important properties.

For example, if you send a GET request to api/users you would expect a list of users with name, email and avatar. You don't need all the properties in the database, so you would use the Minor class; but if you send a GET request to api/users/1, you expect to see much more information than before, right? So in this case you want to use Major class, which has more properties like name, email, avatar, date_of_birth, marital_status and blu_blu_blu.

This way of structuring really helps you when the project is getting bigger. Imagine you have an Order class, which has a one to many relationship with the User class; and you want to send a GET request to api/orders; you expect to see a list of orders and their users, right?

In this case, you could use the Minor class of User model inside the Minor class of Order model to show their relationship! Right?


<?php
 
namespace App\Http\Resources\Order;
 
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\User\Minor as MinorUserResource; // -----> User's minor class
 
class Minor extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'serial' => $this->serial,
            'status' => $this->status,
            'created_at' => $this->created_at,

            'user' => $this->relationLoaded('user') ? 
                          MinorUserResource::make($this->user) : // -----> Hey look at how I used this class here! 
                          null
        ];
    }
}

Using this approach, your data is consistent, and if you want to make a change in one class, that change will be reflected in other classes as well, and you will have created a nice experience in your API.

Note that this is NOT a best practice of any kind; this is what I thought of on my own. I'd be glad if anyone can make this better.

Cheers!