Obioha uche
Mar 21 · 4 min read

Working with Paginated API Response Data in Laravel

This wouldn’t be my first Medium post if I had been courageous enough to confront the demons that have so far inhibited my good intentions to write extensively on my struggles with anxiety, depression and social phobia. I had hoped that writing about my experience so far would perhaps be a meaningful contribution towards reducing the stigma that comes with mental illness in Nigeria. I also hoped it would encourage someone to see a psychotherapist instead of dying in silence. Somehow, instead, I am motivated to write about some issues I have encountered while developing software.

I am an AI/software developer creating predictive machine learning models, chatbots, and web applications to help solve some of the world’s pressing problems.

Given a decent exposure to API endpoints, one would have come across use cases that involve paginated response data. In most cases, the pagination meta information is represented like in the sample below. Working with this is often trivial until some use cases, as will be explained later, are encountered.

pagination: {
“current_page”: 1,
“has_next_page”: true,
“has_previous_page”: false,
“next_page”: 2,
“num_items”: 20,
“num_pages”: 10,
“previous_page”: null
}

The above sample pagination object contains the following fields:

1. current_page: indicates the current page number
2. has_next_page: indicates the presence of a next page
3. has_previous_page: indicates the presence of a previous page
4. next_page: indicates the number of the next page
5. previous_page: indicates the number of the previous page
6. num_items: indicates the total number of items in all the pages combined
7. num_pages: indicates the total number of pages

My initial encounter with this response format left me googling almost endlessly for the optimal way to go about two major challenges I had:

1. Navigation through the pages
2. Exporting to a spreadsheet

Which brings me to the point of this post. I will explain my approach to overcoming these challenges using the Laravel web development framework.

Problem 1: Page Navigation
With the help of a good HTTP client library such as Guzzle, lxudra or some other preferred tool, one could easily retrieve a JSON encoded response data, which can be parsed into a PHP associative array. Since I decided to use Guzzle in my case, I will explain how I used it.

Your route should like this:

Route::get('transactions/{page?}', 'TransactionsController@index');

I instantiated Guzzle in my constructor like so:

public function __construct(GuzzleHttp\Client $client)
{
$this->client = $client;
}

My index method kinda looks like this:

public function index(Request $request, $page = 1)
{
try{
$call = $this->client->get('your_url?page='.$page);
$response = json_decode($call->getBody()->getContents(), true);
}catch (\Exception $e){
//buy a beer
}
$pagination = $response['pagination'];
$numOfpages = $pagination['num_pages'];
$current_page = $pagination['current_page'];
$has_next_page = $pagination['has_next_page'];
$has_previous_page = $pagination['has_previous_page'];
$next_page = $pagination['next_page'];
return view(
'index', compact(
'numOfpages', 'current_page',
'has_next_page', 'has_previous_page', 'next_page',
)
);
}

My blade file, which I chose to call “index.blade.php”, had the following content:

@if(isset($current_page))
<?php
$prev = $current_page - 1;
?>
@if(
($has_next_page == true) && ($has_previous_page == false))
<li><a href="{{url('transactions/'.$next_page)}}">Next</a></li>
@elseif(($has_next_page == false) && ($has_previous_page == true))
<li><a href="{{url('transactions/'.$prev)}}">Previous</a></li>
@elseif(($has_next_page == true) && ($has_previous_page == true))
<li><a href="{{url('transactions/'.$prev)}}">Previous</a></li><li><a href="{{url('transactions/'.$next_page)}}">Next</a></li>
@endif
@endif

With all of the above in place, my first challenge was history.

Problem 2: Exporting to a spreadsheet

You can have a button defined in your “index.blade.php” script, which when clicked would gather all pages and export same to an excel sheet. The code for this would look something like this:

<a class="btn btn-default" href="{{url('fetch-records')}}">Export All Records</a>

While the route definition could look like this:

Route::get('fetch-records', 'TransactionsController@fetchRecords');

And finally you could have the following content in your `fetchRecords` _method_:

$page = 1; //we are starting from the first page
$call = $this->client->get('your_url?page='.$page);
$response = json_decode($call->getBody()->getContents(), true);
$records = $response['data'];
$num_pages = $response['pagination']['num_pages'];
$next_page = $response['pagination']['next_page'];
if($num_pages > 1){
for ($i = $next_page; $i <= $num_pages; $i++){
$call = $this->client->get('your_url?page='.$i);
$response = json_decode($call->getBody()->getContents(), true);
foreach ($data as $datum){
$records[] = $datum;
}
}
}else{
//return default
$records = $response['data'];
}
$transactions = []; //array to hold data from all pages
foreach ($records as $record){
$transactions[] = [
'date' => date('d-m-Y', strtotime($record['created_at'])),
'amount' => $record['amount'],
'handled by' => $record['created_by']
];
}
//Export to excel sheet
\Excel::create('Filename', function($excel) use($transactions) {
$excel->sheet('Sheetname', function($sheet) use($transactions) {
$sheet->fromArray($transactions);
});
})->export('xls');

If all that seemed a bit confusing, let me shed some light on it — like a boss, LOL! 😎

More seriously, in the snippet above, I have set the `page` variable to 1 with `$page = 1`, so that records (“transactions” in this case) are retrieved starting from the first page.

I followed this with an initial call to the API to retrieve the first page. I then checked to confirm if there was more than a single page to process. Having multiple pages would lead me to iterate through as many available pages as is available, using the page numbers as counters and making a fresh API call each time, in order to retrieve the next page.

On the other hand, in the situation where there is only one page, I simply set the `records` variable to the data obtained from the single initial call.

I also looped through the `records` array to retrieve the needed array keys that I would be using, which include created_at, amount and created_by. These were stored in the `transactions` variable.

I now had everything ready for my export — well, except beer 🤒. To complete the export, I very well made use of the Mattwebsite package. This package helped me export the content of the `transactions` variable to an Excel sheet in the “.xls” format, as show in the code above.

And that was how APC retained power. Thank you for stopping by. Your claps are appreciated.

Finally, thank you acetakwas for editing this.

Obioha uche

Written by

AI/Software developer creating awesome stuffs at @70shops.