Skip to content

Commit

Permalink
[Feature] Stats API endpoint (#1994)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexjustesen authored Jan 16, 2025
1 parent e1efde6 commit 840e87f
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 2 deletions.
2 changes: 1 addition & 1 deletion app/Helpers/Bitrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static function bytesToBits(int|float $bytes): int|float
}

// 1 byte = 8 bits
return $bytes * 8;
return round($bytes * 8);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Api/V1/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]);

Expand Down
41 changes: 41 additions & 0 deletions app/Http/Controllers/Api/V1/Stats.php
Original file line number Diff line number Diff line change
@@ -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'),
);
}
}
49 changes: 49 additions & 0 deletions app/Http/Resources/V1/StatResource.php
Original file line number Diff line number Diff line change
@@ -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,
];
}
}
4 changes: 4 additions & 0 deletions routes/api/v1/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -14,4 +15,7 @@

Route::get('/results/{result}', ShowResult::class)
->name('results.show');

Route::get('/stats', Stats::class)
->name('stats');
});

0 comments on commit 840e87f

Please sign in to comment.