-
-
Notifications
You must be signed in to change notification settings - Fork 4
Usage Tracking
Learn how to track and monitor API version usage for analytics and migration planning.
Usage tracking helps you:
- Monitor traffic per API version
- Identify deprecated version usage
- Plan migration timelines
- Detect usage patterns
// config/apiroute.php
'tracking' => [
'enabled' => env('API_VERSION_TRACKING', true),
'driver' => 'database', // 'database', 'redis', 'null'
'table' => 'api_version_stats',
'aggregate' => 'hourly', // 'realtime', 'hourly', 'daily'
],# .env
API_VERSION_TRACKING=truephp artisan vendor:publish --tag="apiroute-migrations"
php artisan migrateSchema::create('api_version_stats', function (Blueprint $table) {
$table->id();
$table->string('version', 10)->index();
$table->string('endpoint')->index();
$table->string('method', 10);
$table->unsignedInteger('requests_count')->default(0);
$table->unsignedInteger('success_count')->default(0);
$table->unsignedInteger('error_count')->default(0);
$table->date('date')->index();
$table->unsignedTinyInteger('hour')->nullable();
$table->timestamps();
$table->unique(['version', 'endpoint', 'method', 'date', 'hour']);
});Default driver. Stores stats in a MySQL/PostgreSQL table.
'tracking' => [
'driver' => 'database',
'table' => 'api_version_stats',
],Pros:
- Queryable with SQL
- Persistent storage
- Easy reporting
Cons:
- Slightly higher latency
- Database space usage
High-performance option for high-traffic APIs.
'tracking' => [
'driver' => 'redis',
],Pros:
- Very fast
- Low latency
- Scalable
Cons:
- Requires Redis
- Less persistent (unless configured)
Disables tracking (for testing).
'tracking' => [
'driver' => 'null',
],Track every request individually.
'aggregate' => 'realtime',Use case: Small APIs, detailed analytics
Aggregate stats per hour.
'aggregate' => 'hourly',Use case: Medium traffic, balanced storage
Aggregate stats per day.
'aggregate' => 'daily',Use case: High traffic, long-term storage
Each tracked request captures:
| Field | Description |
|---|---|
version |
API version (v1, v2, etc.) |
endpoint |
Request path |
method |
HTTP method (GET, POST, etc.) |
requests_count |
Total request count |
success_count |
Successful requests (2xx, 3xx) |
error_count |
Failed requests (4xx, 5xx) |
date |
Date of request |
hour |
Hour of request (if hourly aggregation) |
# All versions (last 30 days)
php artisan api:stats
# Specific period
php artisan api:stats --period=7
# Specific version
php artisan api:stats --api-version=v1
# JSON output
php artisan api:stats --jsonAPI Version Usage Statistics (Last 30 days)
Total Requests: 1,234,567
┌──────────────────────┬────────────┬────────────┬──────────┬────────┐
│ Version │ Requests │ Percentage │ Success │ Errors │
├──────────────────────┼────────────┼────────────┼──────────┼────────┤
│ v2 │ 967,901 │ 78.4% │ 960,123 │ 7,778 │
│ v1 (deprecated) │ 240,741 │ 19.5% │ 238,456 │ 2,285 │
│ v3 │ 25,925 │ 2.1% │ 25,800 │ 125 │
└──────────────────────┴────────────┴────────────┴──────────┴────────┘
use Grazulex\ApiRoute\Contracts\VersionTrackerInterface;
class ApiAnalyticsController extends Controller
{
public function __construct(
private VersionTrackerInterface $tracker
) {}
public function stats()
{
// Get all stats for last 30 days
$stats = $this->tracker->getAllStats(30);
// Get stats for specific version
$v1Stats = $this->tracker->getStats('v1', 30);
return response()->json([
'all' => $stats,
'v1' => $v1Stats,
]);
}
}{
"all": {
"v1": {
"total_requests": 240741,
"success_requests": 238456,
"error_requests": 2285
},
"v2": {
"total_requests": 967901,
"success_requests": 960123,
"error_requests": 7778
}
},
"v1": {
"total_requests": 240741,
"success_requests": 238456,
"error_requests": 2285
}
}<?php
namespace App\Tracking;
use Grazulex\ApiRoute\Contracts\VersionTrackerInterface;
class CustomTracker implements VersionTrackerInterface
{
public function track(
string $version,
string $endpoint,
string $method,
int $status
): void {
// Custom tracking logic
// Send to analytics service, etc.
}
public function getStats(string $version, int $days): array
{
// Custom stats retrieval
}
public function getAllStats(int $days): array
{
// Custom all stats retrieval
}
}// In AppServiceProvider
use App\Tracking\CustomTracker;
use Grazulex\ApiRoute\Contracts\VersionTrackerInterface;
public function register(): void
{
$this->app->bind(VersionTrackerInterface::class, CustomTracker::class);
}Tracking is done asynchronously after the response is sent:
dispatch(function () use ($request, $response) {
$this->tracker->track(...);
})->afterResponse();This ensures zero impact on API response time.
For high-traffic APIs, use Redis:
'tracking' => [
'driver' => 'redis',
'aggregate' => 'hourly', // Reduce write frequency
],Implement cleanup for old stats:
// In a scheduled command
DB::table('api_version_stats')
->where('date', '<', now()->subDays(90))
->delete();// config/apiroute.php
'notifications' => [
'enabled' => true,
'events' => [
'high_deprecated_usage' => 50, // Warn if > 50% on deprecated
],
],use Grazulex\ApiRoute\Contracts\VersionTrackerInterface;
class DeprecatedUsageChecker
{
public function __construct(
private VersionTrackerInterface $tracker
) {}
public function check(): void
{
$stats = $this->tracker->getAllStats(7);
$total = array_sum(array_column($stats, 'total_requests'));
foreach ($stats as $version => $data) {
$percentage = ($data['total_requests'] / $total) * 100;
if ($version === 'v1' && $percentage > 20) {
// Send alert
Notification::send(
$admins,
new HighDeprecatedUsageNotification($version, $percentage)
);
}
}
}
}class ApiDashboardController extends Controller
{
public function index()
{
$stats = DB::table('api_version_stats')
->select('version', 'date')
->selectRaw('SUM(requests_count) as requests')
->selectRaw('SUM(success_count) as success')
->selectRaw('SUM(error_count) as errors')
->where('date', '>=', now()->subDays(30))
->groupBy('version', 'date')
->orderBy('date')
->get();
return view('dashboard.api', compact('stats'));
}
}- Artisan Commands - CLI for viewing stats
- Events - React to version events
- Version Lifecycle - Plan migrations with data
Laravel ApiRoute - Complete API versioning lifecycle management for Laravel
Home | Getting Started | Examples | Configuration
Made with ❤️ for the Laravel community