cloudcreativity/laravel-json-api

Custom Controller with fetching of multiple resources

ranferi opened this issue · 9 comments

Hi, I'm trying to implement a custom controller that will return a custom json with zero or more resources of my API.

In my API, there's resources like Brands, Colors, Materials, etc. and I created a controller just like the documentation says:

class CatalogsController extends JsonApiController
{
    public function index(StoreInterface $store, FetchResources $request): Response
    {  }
}

to send zero or multiples resources in this custom json:

{
   "data": [{
      "brands": []
   },
   {
      "materials": []
   }
   ]
}

I added my custom controller and action to the api route:
$api->get('/catalogs', [CatalogsController::class, 'index']);

This endpoint may receive a array with the resource names (in the request) that want to get back:
['brands', 'materials' ]

So far I only have this code in my action 'index' (there's more logic to get the singular of the resoures from the request array) :

$model = "App\Models\Brand";
$resource = $model::all();
return $this->reply()->content($resource);

which returns correctly all the data from Brands.

UPDATE: this code reflect better what I want to achieve:

$catalogs = ['brands'];
$json = [];

foreach ($catalogs as $catalog ) {
    $modelName = Str::ucfirst(Str::singular($catalog));
    $model = "App\Models\Catalogs\\$modelName";
    $resource = $model::all();
    $json[$catalog] = $this->reply()->content($resource);
}

return['data' => $json];

with this response (cut to be brief):

 "data": {
        "brands": {
            "headers": {},
            "original":"{\"data\":[{\"type\":\"brands\",\"id\":\"1\",\"attributes\":{\"name\":\"#FR2\",\"brandEcommerceId\":495,\"active\":1,\"createdAt\":\"2020-07-08T00:38:02.000000Z\",

How can I get the data from a resource and added to a custom Json using the laravel-json-api package?

$catalogs = ['brands'];
$models = collect();

foreach ($catalogs as $catalog ) {
    $modelName = Str::ucfirst(Str::singular($catalog));
    $model = "App\Models\Catalogs\\$modelName";
    $models->merge($model::all());
}

return $this->reply()->content($models);

Thanks @lindyhopchris! now I have the data I want on the response. The only think I have to modified is $models->merge($model::all()); to $models = $models->merge($model::all());. Reading the docs the reply() method can help to shape the response but there's still no documentation on the chapter about responses. Is there a way to modify the response to look like the structure I talk in my post?

"data": [{
      "colors": [
          {
            "type": "colors",
            "id": "1",
            "attributes": {
                "name": "Black",
                "active": 0,
                "createdAt": "2019-05-03T01:06:58.000000Z",
                "updatedAt": "2019-05-03T01:06:58.000000Z"
            },
            "links": {
                "self": "http://api.test/api/v1/colors/1"
            }
        }
      ]
   }, {
      "brands": []
   }
]

Is it correct that this isn't valid JSON:API?

@ranferi the structure you want isn't valid JSON:API.

Hi. Yeah I know. Another third party team ask me for this specific API endpoint. All my other endpoints follows the JSONAPI specifications. I made negotiations to return the data as the JSONAPI (with ID, type, attributes) but they want at least the names of every catalog as the properties just like the json structure I post. That's why I was asking if there's a way to change the returned json

You'd need to encode it yourself, as obviously this package can only encode to the specifcation.

To encode a single model to its JSON:API representation, use:

$encoder = json_api()->encoder();
$resource = $encoder->serializeData($model)['data'];

PS: if you have multiple APIs, you'll need to provide the name of the API to the json_api() helper.

@lindyhopchris Thank you for your help!!

No problem!