uttamrabadiya/api-version-manager
Installation
composer require uttamrabadiya/api-version-manager
Publish the config file:
php artisan vendor:publish --provider="Uttamrabadiya\ApiVersionManager\ApiVersionManagerServiceProvider" --tag="config"
Configure API Versioning
Edit config/api-version-manager.php to define your versioning strategy (e.g., header, query, path).
Define Versions
In app/Providers/ApiVersionManagerServiceProvider.php, register your API versions:
public function boot()
{
ApiVersionManager::addVersion('v1', 'App\Http\Requests\V1\*Request');
ApiVersionManager::addVersion('v2', 'App\Http\Requests\V2\*Request');
ApiVersionManager::setFallbackVersion('v1'); // Fallback to v1 if no version is specified
}
First Use Case
Create a versioned request class (e.g., app/Http/Requests/V1/GetUserRequest.php) and use it in a controller:
use App\Http\Requests\V1\GetUserRequest;
public function show(GetUserRequest $request)
{
// Automatically resolves to V1 logic
}
Version-Specific Requests
Place versioned requests in app/Http/Requests/V{version}/ (e.g., V1/GetUserRequest.php). The package auto-resolves them based on the API version header/query/path.
Fallback Logic
Use setFallbackVersion() in ApiVersionManagerServiceProvider to handle unsupported versions gracefully:
ApiVersionManager::setFallbackVersion('v1');
Resource Integration
Extend JsonResource with versioned logic:
namespace App\Http\Resources\V1;
use App\Http\Resources\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return ['id' => $this->id, 'name' => $this->name]; // V1-specific fields
}
}
Reference in controllers:
return new \App\Http\Resources\V1\UserResource($user);
Leverage route versioning via middleware or groups:
Route::middleware(['api-version' => 'v1'])->group(function () {
Route::get('/users', [UserController::class, 'index']);
});
Maintain a single controller while dynamically loading versioned logic:
public function store(Request $request)
{
$versionedRequest = ApiVersionManager::resolveRequest($request, StoreUserRequest::class);
// $versionedRequest now points to V1/V2/StoreUserRequest
}
Namespace Conflicts
Ensure versioned requests/resources are namespaced correctly (e.g., V1\*Request). Avoid overlapping class names like GetUserRequest in both V1 and V2.
Middleware Order
Place the api-version middleware before throttle or auth to ensure version resolution occurs first:
$router->middleware('api-version');
$router->middleware('throttle:60,1');
Fallback Misconfiguration
If setFallbackVersion() is omitted, unsupported versions return 404. Always define a fallback for production.
Caching Headers
Versioned routes may break cached responses if headers (e.g., Accept: application/vnd.api.v1+json) are used for versioning. Exclude versioned routes from caching or use Cache::forever().
Check Resolved Version Log the resolved version in middleware:
public function handle($request, Closure $next)
{
\Log::info('Resolved API version:', ['version' => ApiVersionManager::getVersion()]);
return $next($request);
}
Validate Request Resolution
Use tinker to test request resolution:
php artisan tinker
>>> $request = new \Illuminate\Http\Request(['_version' => 'v2']);
>>> \Uttamrabadiya\ApiVersionManager\Facades\ApiVersionManager::resolveRequest($request, \App\Http\Requests\GetUserRequest::class);
Custom Version Detection
Override version detection logic in app/Providers/ApiVersionManagerServiceProvider:
ApiVersionManager::setVersionDetector(function ($request) {
return $request->header('X-Custom-Version') ?: 'v1';
});
Dynamic Version Loading Load versioned classes dynamically (e.g., for plugins):
ApiVersionManager::addVersion('v3', function () {
return class_exists('App\Http\Requests\V3\*Request') ? 'App\Http\Requests\V3\*Request' : null;
});
Resource Fallbacks Implement fallback resources for unsupported versions:
ApiVersionManager::setResourceFallback(\App\Http\Resources\V1\UserResource::class);
How can I help you explore Laravel packages today?