Api resource error when query result is null as follow in official document example.
public function show($id)
{
return new UserResource(User::find($id));
}
Assume that $id = 20 and there is no user with id = 20
Can you also post the error you are getting or the stack trace?
What happens if you update to latest Laravel version?
@GuidoHendriks I have tried to upgrade to 5.5.32 the error is still here
@priidikvaikla
Error log:
{
"message": "Call to a member function toArray() on null",
"exception": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",
"file": "/home/vagrant/project/vendor/laravel/framework/src/Illuminate/Http/Resources/Json/Resource.php",
"line": 113,
}
Here is in my UserResource:
public function toArray($request)
{
return parent::toArray($request);
}
The responsibility of a resource class is to transform your model into JSON. That obviously isn't gonna work when you pass null. You better check for existence of the model in your controller, or use findOrFail to automatically trigger a 404.
But this isn't the place for code level support, this is for reporting bugs and issues of the framework.
@GuidoHendriks OK, then the official document should not use something like ::find($id). The doc made me think that it doesn't require to check for null before using it, the expectation is something like null value in data key.
@fokoz I just checked the documentation, it's actually not using find($id), just find(1). That's no more than a placeholder. The default implementation of a resource calls toArray() on the passed object.
You are free to build upon your resource class as much as you like. I rarely use the parent class toArray default that is provided. I usually build up what I want my toArray method to return, including nested resources etc.
I agree you probably want to check the existence of the entity first, or use the findOfFail and handle your error however you like to handle errors.
Alternatively if you really want to remain with potentially passing a null to your resource then check for it in your toArray.. you can simply check if $this->resource is null and perform what logic you like as a default.
I have already use findOrFail but just curious because of the document. ($id) or (1) is the same because there is no guarantee that id=1 would exist. IMO, It is the same logic for null object pattern which was introduced in eloquent relation as withDefault() to reduce existence checking code.
Then your issue is solvable. If you think it鈥檚 wrong submit a PR for the docs. I think it鈥檚 just implying though that a model should be passed to the resource, not to be taken literally as the only way it can be used.
If you guys think it is ok in the first place, so be it. By the way, I think it should at least not return 500 error for null result. I knowed about 500 because I passed wrong id by mistake, otherwise I would not use findOrFail.
For suggestions and feature requests please use the https://github.com/laravel/internals repo.
I just overrided the Resource@resolve() method, to handle these kinds of cases by adding this to the start of the method.
public function resolve($request = null)
{
if($this->resource == null){
return null;
....
}
I just overrided the Resource@resolve() method, to handle these kinds of cases by adding this to the start of the method.
public function resolve($request = null) { if($this->resource == null){ return null; .... }
If only this was baked right inside the resource! Could you submit the PR to Laravel Ideas repo if it is not captured in yet?
I just overrided the Resource@resolve() method, to handle these kinds of cases by adding this to the start of the method.
public function resolve($request = null) { if($this->resource == null){ return null; .... }If only this was baked right inside the resource! Could you submit the PR to Laravel Ideas repo if it is not captured in yet?
Actually, upgrading to 5.7/5.8 version, passing null is taken care of. There should be a PR to the 5.6 branch though.
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
if (is_null($this->resource)) {
return [];
}
return is_array($this->resource)
? $this->resource
: $this->resource->toArray();
}
But you will still get error if return a transformation array instead of return parent::toArray($request);:
class User extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
}
public function show($id)
{
return new UserResource(null);
}
{
"message": "Trying to get property 'id' of non-object",
"exception": "ErrorException",
"file": "vendor\\laravel\\framework\\src\\Illuminate\\Http\\Resources\\DelegatesToResource.php",
"line": 120,
"trace": [
...
]
}
Most helpful comment
The responsibility of a resource class is to transform your model into JSON. That obviously isn't gonna work when you pass null. You better check for existence of the model in your controller, or use
findOrFailto automatically trigger a 404.But this isn't the place for code level support, this is for reporting bugs and issues of the framework.