R
R
Rooly2021-04-12 14:44:51
Laravel
Rooly, 2021-04-12 14:44:51

How to properly work with JsonResource in Laravel?

Colleagues, I ask for your help! ¯\(ツ)/¯

I am writing a backend REST-api component for one project.

I have an api-route domain.ru/api/offices, which should return a list of offices and employees (employees) working in each office.

I have created an OfficeResource and an OfficeCollection to get one and many offices respectively, also give the code of EmployeeResource

OfficeResource

return [
            "id" => $this->id,
            "code" => $this->code,
            "address" => $this->address,
            "employees" => new EmployeeCollection($this->employees),
            "created_at" => $this->created_at
];


EmployeeResource
return [
            "id" => $this->id,
            "name" => $this->name,
            "office" => $this->office
];


For collections, I simply created EmployeeCollection and OfficeCollection using the artisan interface and did not change anything there (well, as always done) ¯\(ツ)/¯

api.php code
Route::get('offices', function (Request $request) {
    $office_collection = new OfficeCollection(Office::all());
    foreach ($office_collection as $office) {
        foreach ($office->employees as $employee) {
            unset($employee['id_office']);
        }
    }
    return response()->json([
        "status" => true,
        "response" => $office_collection,
    ], 200);
});


So here's the problem, I have a domain.ru/api/employees route that should return all employees and the office of each employee they work in. But I also have a domain.ru/api/offices route that returns offices and employees working in them

. Just in the domain.ru/api/employees route, I must include the office in the Json response, and in the domain.ru/api/offices route, the office will be, as it were, "main" and the employee will enter it and there he should not be included. The only thing I've come up with is to unset the office with foreach. Do you think this is correct? It seems that there should be only one JSONResource (judging by the tutorials that I looked at), but I just can’t understand how I can do it without a crutch.

here is what happens in my "crutch" code. It’s like my office remains null, but damn it, this is 100% wrong

{
    "status": true,
    "response": [
        {
            "id": 1,
            "code": "e4bK4A0UIE",
            "address": "Ленина, 10",
            "employees": [
                {
                    "id": 7,
                    "name": "Elyssa Grady",
                    "office": null
                },
                {
                    "id": 8,
                    "name": "Manuel Schimmel",
                    "office": null
                },
                {
                    "id": 10,
                    "name": "Thelma Vandervort",
                    "office": null
                }
            ],
            "created_at": "2021-04-11T12:50:56.000000Z"
        },
}


in principle, with a crutch, everything works correctly for me --> domain.ru/api/employees returns what is needed (I attached the code below), but I think this is a completely wrong approach, that I manually unset something

api.php

Route::get('employees', function (Request $request) {
    return response()->json([
        "status" => true,
        "response" => new EmployeeCollection(Employee::all())
    ], 200);
});


return response domain.ru/api/employees
{
    "status": true,
    "response": [
        {
            "id": 1,
            "name": "Schuyler Kilback",
            "office": {
                "id": 4,
                "code": "8ZJzJpdNe!",
                "address": "ySm7XUUIgpkWYfuHoaFG",
                "created_at": "2021-04-11T12:50:56.000000Z"
            }
        },
     ]
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey Ukolov, 2021-04-12
@ZetIndex_Ram

The whenLoadedmethod may be used to conditionally load a relationship. In order to avoid unnecessarily loading relationships, this method accepts the name of the relationship instead of the relationship itself:

use App\Http\Resources\PostResource;

/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'posts' => PostResource::collection($this->whenLoaded('posts')),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

In this example, if the relationship has not been loaded, the posts key will be removed from the resource response before it is sent to the client.
https://laravel.com/docs/8.x/eloquent-resources#co...
The doc is about a collection, you have one model, but everything else applies.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question