I have inherited a PHP project, it is written in Laravel 9.2.
There is a particular endpoint in the application that needs quite a bit of work. I’ll post the code below.
It accepts a POST request with an array of IDs in the body. Iterates over the IDs and queries an external API, building a list of response data. Loops over the responses, and the categories within each response and runs a calculation adding the result to the total variable. Eventually returning the results.
There are some requirements for the endpoint, which I cannot change. It must accept and array of IDs in the request body, it must query the external API asynchronously, it must return the array of data with the totals of each category_id
from each request combined.
More importantly the endpoint needs to be secure, reliable, scalable, available, maintainable and performant. There could be any number of IDs passed into the endpoint, potentially hundreds, and for each ID there could be hundreds (or more) categories inside each external API requests JSON body.
How would you refactor this endpoint? I’m considering using asynchronous jobs queues, but it makes it difficult to return a response to the User, which needs to be a combination of the output of each job. I would like to return an ID/s from the endpoint and leave it up to the consumer of the endpoint to poll another endpoint to check if the job has finished. Curious to hear other peoples thoughts as to how they would approach this…
<?php
namespace AppHttpControllers;
use AppHttpRequestsReportRequest;
use IlluminateHttpRequest;
use IlluminateSupportFacadesHttp;
class CategoryReportController extends Controller
{
/**
* @param Request $request
*/
public function categoryReportTotals(ReportRequest $request)
{
$responses = [];
foreach ($request->parent_category_ids as $parentCategoryId) {
$responses[] = Http::withBasicAuth('username', 'password')->get('https://api.endpoint.com/category/' . $parentCategoryId . '?version=5&associated=true');
}
$grouped = [];
$categoryATotal = 0;
$categoryBTotal = 0;
$categoryCTotal = 0;
foreach ($responses as $response) {
$json = $response->json();
$categories = $json['data']['CategoryList'];
foreach ($categories as $category) {
$grouped[$category['category_id']] = $category;
if ($category['category_id'] == 1) {
$categoryCTotal = $categoryATotal + ($category['category_count_start'] + $category['count']);
} else if ($category['category_id'] == 2) {
$categoryCTotal = $categoryBTotal + ($category['category_count_start'] + $category['distinct']);
} else if ($category['category_id'] == 3) {
$categoryCTotal = $categoryCTotal + ($category['category_count_start'] + $category['count']);
}
}
}
$results = [
[
'category_id' => 1,
'total' => $categoryATotal,
],
[
'category_id' => 2,
'total' => $categoryBTotal,
],
[
'category_id' => 3,
'total' => $categoryCTotal,
]
];
return response()->json([
'data' => $results
]);
}
}
I’ve also considered leaning on a database. Each time a request it made, saving a row in a table with the array of IDs, then saving the required data for the calculations in another table.
Thomas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.