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

Brandon.css's avatar

Laravel API Controller add paginate meta values to response

I have an API and I'm using Resource and Resource Collections.

I have an API controller with the following

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $stores = Store::paginate(2);

        return $this->sendResponse(new StoreCollection($stores), 'Stores retrieved successfully.');
    }

My API Base controller is as follows:

  /**
     * @param        $result
     * @param string $message
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function sendResponse($result, string $message): \Illuminate\Http\JsonResponse
    {
        $response = [
            'success' => true,
            'status'  => 200,
            'code'    => 'success',
            'message' => $message,
            'data'    => $result,
        ];

        return response()->json($response, 200);
    }

The response is this:

{
    "success": true,
    "status": 200,
    "code": "success",
    "message": "Stores retrieved successfully.",
    "data": [
        {
            "id": 1,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        },
        {
            "id": 2,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        }
    ]
}

How am I able to add the meta array to the response with the paginate values?? Or is there a better way to do this?

I want to have the response so it's like this:

{
    "success": true,
    "status": 200,
    "code": "success",
    "message": "Stores retrieved successfully.",
    "data": [
        {
            "id": 1,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        },
        {
            "id": 2,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        }
    ],
    "links": {
        "first": "http://localhost/api/v1/stores?page=1",
        "last": "http://localhost/api/v1/stores?page=347",
        "prev": null,
        "next": "http://localhost/api/v1/stores?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 347,
        "path": "http://localhost/api/v1/stores",
        "per_page": 2,
        "to": 2,
        "total": 693
    }
}


0 likes
6 replies
Brandon.css's avatar

I can do this and get the meta to show:

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $stores = Store::paginate(2);

        // return $this->sendResponse(new StoreCollection($stores), 'Stores retrieved successfully.');
        return new StoreCollection(Store::paginate(2));
    }

But then I'm missing everything at the top of my response (success, status, code, message)

{
    "data": [
        {
            "id": 1,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        },
        {
            "id": 2,
            "name": "Toronto-Central Dufferin & Bloor",
            "location_number": 648,
            "latitude": "43.6574",
            "longitude": "-79.43663",
            "tel": "531-6074",
            "fax": "531-7237",
            "address": "900 DUFFERIN STREET",
            "address2": "UNIT 366",
            "postal_code": "M6H 4A9",
            "city": "TORONTO-CENTRAL",
            "district": "Toronto West",
            "manager_name": "SHAWN STEDMANN",
            "created_at": "12/08/2020",
            "updated_at": "12/08/2020"
        }
    ],
    "links": {
        "first": "http://localhost/api/v1/stores?page=1",
        "last": "http://localhost/api/v1/stores?page=347",
        "prev": null,
        "next": "http://localhost/api/v1/stores?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 347,
        "path": "http://localhost/api/v1/stores",
        "per_page": 2,
        "to": 2,
        "total": 693
    }
}

martinbean's avatar

@brandon.css In terms of HTTP and RESTful API best practices, you don’t need to include status, success, and code keys in your response. The status code should be sent with HTTP response, and “success” can be inferred by the status code. For example, 200 OK should never be used if the request failed.

Just return the collection as it’s intended to be:

public function index()
{
    $stores = Store::paginate(2);

    return new StoreCollection($stores);
}
2 likes
Brandon.css's avatar

Ahh, I was hoping to have custom stuff in the response to handle errors and stuff, but I guess I'll do that client-side.

Thanks for the reply! I'll just do it this way.

ApexLeo's avatar

Senario

@brandon.css if you want to return single row then use new ModelResource($modele) and if you want to return a collection then use ModelResource::collection($models)


// for single record
return new ModelResource( Model::latest()->first() );

// for collection with or without pagination
return ModelResource::collection( Model::latest()->paginate() );

if you use second approach it will add meta tags it self as u mention above .

Problem

Problem is when u use response()->jason() then meta tags won't work

Solution

in that senario this is what i do first of all i create two resource classes for the same model as you can see.

.
+-- Http
|   +-- Resources
|   |   +-- Store (Store is model name in your case)
|   |   |   +-- StoreCollection
|   |   |   +-- StoreResource

for more info about ModelCollection & ModelResource see this Laravel Api Resource

now in StoreResource write your code as you normally do


    public function toArray($request)
    {
        return [
            "id" => $this->slug,
            "name" => $this->name,
            // etc
        ];
    }

now in StoreCollection this is what i do to paginate my model.


    public function toArray($request)
    {
        return [
            'data' => StoreResource::collection($this->collection),
            'pagination' => [
                "current_page" => $this->currentPage(),
                "first_page_url" =>  $this->getOptions()['path'].'?'.$this->getOptions()['pageName'].'=1',
                "prev_page_url" =>  $this->previousPageUrl(),
                "next_page_url" =>  $this->nextPageUrl(),
                "last_page_url" =>  $this->getOptions()['path'].'?'.$this->getOptions()['pageName'].'='.$this->lastPage(),
                "last_page" =>  $this->lastPage(),
                "per_page" =>  $this->perPage(),
                "total" =>  $this->total(),
                "path" =>  $this->getOptions()['path'],
            ],
        ];
    }

now in controller


// if you want to return single record
return response()->json( new ModelResource( Model::latest()->first() ), 200 );

// and for collection with pagination
return response()->json( new ModelCollection(Model::paginate()), 200 );


// you can also add other info
return response()->json([ 'data' => new ModelCollection(Model::paginate()), 'success' => true ], 200 );

for more info about pagination in StoreCollection visit this link Laravel Pagination

marcgaumont's avatar

@ApexLeo Very helpful, had the same problem as him and just ended up copying the "'pagination' => " block to my Collection and it works perfectly ! thanks !

Please or to participate in this conversation.