Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

craigivemy's avatar

Response() not respecting API resource structure

I have a strange (at least to my tired eyes) problem where using the response() function to return an API resource is ignoring the with() method of said resource, and also not adding the 'data' key wrapping. Strangely the latter issue is only on single resources, not on collections.

The method using the response() function is in my API controller, which is extended by my other controllers.

ApiController

class ApiController extends Controller
{
    public function respond($data, int $status_code = 200)
    {
        try {
            // this is where the issue is
            // simply returning $data prevents the issue
            return response($data)->setStatusCode($status_code);
        } catch (Throwable $t) {
            $this->logger->log('critical', $t->getMessage(), ['exception' => $t]);
            return $this->respondWithError(500);
        }
    }
...
}

ClubController

use App\Http\Resources\Club as ClubResource;
use App\Http\Resources\ClubCollection;
...

class ClubController extends ApiController
{

    /**
     * Display a listing of the resource.
     *
     * @return ClubCollection
     */
    public function index()
    {
       // returns with data key wrapping, but ignores the with() method on the resource
      // collection
       return $this->respond(new ClubCollection(Club::all()));
    }

    public function show($id)
    {
        
            // returns with no wrapping, and also doesn't implement resource with() method
            return $this->respond(new ClubResource(Club::findOrFail($id)));
    }
...
}

ClubCollection Resource

class ClubCollection extends ResourceCollection
{
    /**
     * Transform the resource collection into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'data'  => $this->collection,
            'links' => [
                'self'  => 'link-value'
            ],
            'status'    => 'success'
        ];
    }
    
    // doesn't get called
    public function with($request)
    {
        return [
            'test' => 'this will be ignored '
        ];
    }
}

Club Resource

class Club 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,
            'primary_color'     => $this->primary_colour,
            'secondary_colour'  => $this->secondary_colour,
            'tertiary_colour'   => $this->tertiary_colour,
            'logo_url'          => $this->logo_url,
            'narrative'         => $this->narrative
        ];
    }
    
    // doesn't get called
    public function with($request)
    {
        return [
            'status'    => 'this will be ignored'
        ];
    }

}

To clarify, neither the index or show endpoints result in the with() method being called. More importantly, the show method also returns the data flat, with no 'data' key wrapping it.

0 likes
7 replies
D9705996's avatar

Is there any reason you need to have the respond method in your API controller?

Can you not do in you Club controller.

    public function index()
    {
       
       return new ClubCollection(Club::all());
    }

    public function show($id)
    {        
            return new ClubResource(Club::findOrFail($id)));
    }

The findOrFailWill throw a 404 if club doesnt exist. I think you respond method is messing with some laravel magic

craigivemy's avatar

I could, but I'd prefer to abstract the response methods (I have ones for respondCreated, respondNotFound etc) to standardise the API responses and prevent lots of work down the line if anything changes.

Strange that exactly the same method is called for both controller functions but only on the show() the problem occurs?

Also - I do have code to catch the ModelNotFoundException.

D9705996's avatar
D9705996
Best Answer
Level 51

Ok then in your respond method can you change you try block to

return $data->response()->setStatusCode($status_code);

I think this should work but not tested.

craigivemy's avatar

That does work - though I'm concerned it is now dependent on the data being something that inherits the response() function?

D9705996's avatar

You could type hint \Illuminate\Http\Resources\Json\Resource in your respond method signature to ensure you are dealing with a resource or collection in your ApiController which will have response() available.

1 like
D9705996's avatar

@craigivemy - has the above solved your problem. if so can you please mark as solved to help others who may be looking for a solution to the same problem. If not let me know how I can help

craigivemy's avatar

Sorry could only test this morning - it does, and type hinting gives me a way to enforce certain business logic.

Curious to know why it wasn't working though - using response in the way I did originally is how it is often used in the docs.

Please or to participate in this conversation.