mirror of
https://github.com/alexjustesen/speedtest-tracker.git
synced 2026-06-23 04:10:25 +00:00
[Feature] Stats API endpoint (#1994)
This commit is contained in:
@@ -32,7 +32,7 @@ class Bitrate
|
||||
}
|
||||
|
||||
// 1 byte = 8 bits
|
||||
return $bytes * 8;
|
||||
return round($bytes * 8);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,10 +17,11 @@ abstract class ApiController
|
||||
* @param int $code
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public static function sendResponse($data, $message = 'ok', $code = 200)
|
||||
public static function sendResponse($data, $filters = [], $message = 'ok', $code = 200)
|
||||
{
|
||||
$response = array_filter([
|
||||
'data' => $data,
|
||||
'filters' => $filters,
|
||||
'message' => $message,
|
||||
]);
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Http\Resources\V1\StatResource;
|
||||
use App\Models\Result;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Spatie\QueryBuilder\Enums\FilterOperator;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
|
||||
class Stats extends ApiController
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*/
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$stats = QueryBuilder::for(Result::class)
|
||||
->selectRaw('count(*) as total_results')
|
||||
->selectRaw('avg(ping) as avg_ping')
|
||||
->selectRaw('avg(download) as avg_download')
|
||||
->selectRaw('avg(upload) as avg_upload')
|
||||
->selectRaw('min(ping) as min_ping')
|
||||
->selectRaw('min(download) as min_download')
|
||||
->selectRaw('min(upload) as min_upload')
|
||||
->selectRaw('max(ping) as max_ping')
|
||||
->selectRaw('max(download) as max_download')
|
||||
->selectRaw('max(upload) as max_upload')
|
||||
->AllowedFilters([
|
||||
AllowedFilter::operator(name: 'start_at', internalName: 'created_at', filterOperator: FilterOperator::DYNAMIC),
|
||||
AllowedFilter::operator(name: 'end_at', internalName: 'created_at', filterOperator: FilterOperator::DYNAMIC),
|
||||
])
|
||||
->first();
|
||||
|
||||
return self::sendResponse(
|
||||
data: new StatResource($stats),
|
||||
filters: $request->input('filter'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\V1;
|
||||
|
||||
use App\Helpers\Bitrate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class StatResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'ping' => [
|
||||
'avg' => round($this->avg_ping, 2),
|
||||
'min' => round($this->min_ping, 2),
|
||||
'max' => round($this->max_ping, 2),
|
||||
],
|
||||
'download' => [
|
||||
'avg' => round($this->avg_download),
|
||||
'avg_bits' => $this->when($this->avg_download, fn (): int|float => Bitrate::bytesToBits($this->avg_download)),
|
||||
'avg_bits_human' => $this->when($this->avg_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->avg_download)).'ps'),
|
||||
'min' => round($this->min_download),
|
||||
'min_bits' => $this->when($this->min_download, fn (): int|float => Bitrate::bytesToBits($this->min_download)),
|
||||
'min_bits_human' => $this->when($this->min_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->min_download)).'ps'),
|
||||
'max' => round($this->max_download),
|
||||
'max_bits' => $this->when($this->max_download, fn (): int|float => Bitrate::bytesToBits($this->max_download)),
|
||||
'max_bits_human' => $this->when($this->max_download, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->max_download)).'ps'),
|
||||
],
|
||||
'upload' => [
|
||||
'avg' => round($this->avg_upload),
|
||||
'avg_bits' => $this->when($this->avg_upload, fn (): int|float => Bitrate::bytesToBits($this->avg_upload)),
|
||||
'avg_bits_human' => $this->when($this->avg_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->avg_upload)).'ps'),
|
||||
'min' => round($this->min_upload),
|
||||
'min_bits' => $this->when($this->min_upload, fn (): int|float => Bitrate::bytesToBits($this->min_upload)),
|
||||
'min_bits_human' => $this->when($this->min_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->min_upload)).'ps'),
|
||||
'max' => round($this->max_upload),
|
||||
'max_bits' => $this->when($this->max_upload, fn (): int|float => Bitrate::bytesToBits($this->max_upload)),
|
||||
'max_bits_human' => $this->when($this->max_upload, fn (): string => Bitrate::formatBits(Bitrate::bytesToBits($this->max_upload)).'ps'),
|
||||
],
|
||||
'total_results' => $this->total_results,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
use App\Http\Controllers\Api\V1\LatestResult;
|
||||
use App\Http\Controllers\Api\V1\ListResults;
|
||||
use App\Http\Controllers\Api\V1\ShowResult;
|
||||
use App\Http\Controllers\Api\V1\Stats;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('v1')->name('api.v1.')->group(function () {
|
||||
@@ -14,4 +15,7 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
|
||||
|
||||
Route::get('/results/{result}', ShowResult::class)
|
||||
->name('results.show');
|
||||
|
||||
Route::get('/stats', Stats::class)
|
||||
->name('stats');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user