Merge Json/Resource::with() when using a collection in an API Resource
joshuadegier opened this issue · 1 comments
When using API resources in Laravel 5.5 you're able to add additional keys to the response when using a single resource by adding a with()
method to your Resource, like below. Jeffrey Way mentioned this already in one of his video's about What's new in Laravel 5.5: API Resources
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class UserResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
public function with($request)
{
return [
'version' => '1.0',
'success' => true,
];
}
}
Examples
response for return UserResource(User::first());
:
response for return UserResource::collection(User::limit(2)->get())
:
expected behaviour / response (made with the draft below):
Current behaviour
Works for single resources, not for collections.
Expected behaviour
I was expecting these extra key/values to be added in all responses returned by UserResource, also if I used the collection helper method.
Solution
Below is a first draft that adds the values from userResource::with()
to the collection response using the additional()
method I found. I modified Illuminate\Http\Resources\Json\Resource::resolve()
to check for an instance of ResourceCollection and then newing up an empty Resource for the objects it collects ($this->collects
) and returning the values from the with()
method.
My current draft looks like below:
/**
* Resolve the resource to an array.
*
* @param \Illuminate\Http\Request|null $request
* @return array
*/
public function resolve($request = null)
{
$data = $this->toArray(
$request = $request ?: Container::getInstance()->make('request')
);
if (is_array($data)) {
$data = $data;
} elseif ($data instanceof Arrayable || $data instanceof Collection) {
$data = $data->toArray();
} elseif ($data instanceof JsonSerializable) {
$data = $data->jsonSerialize();
}
if($this instanceof ResourceCollection) {
return $this->additional((new $this->collects(null))->with($request))->filter((array) $data);
} else {
return $this->filter((array) $data);
}
}
The example above is tested using a single resource and various kinds of collections (pagination, limited, full result list) and seem to work. It doesn't overwrite the reserved keys like links
or meta
.
This is a first time for me to suggest an addition to the framework. So I'm not even sure if I was hooking this in the right place or not. I hope to find some help or useful tips on how to get this tested and checked and wether or not this is even worth considering to add to the framework.
You'll need to have a separate resource collection that extends Illuminate\Http\Resources\Json\ResourceCollection
where you can add a with()
method.
This is the only way for Laravel to know if these extra keys should be in collection response or single resource response or both.