jeromejhipolito / laravel-api-versioning
Header-based API versioning with version flags for Laravel. Supports semantic versioning and feature flag-like version control.
Installs: 68
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/jeromejhipolito/laravel-api-versioning
Requires
- php: ^8.2
- illuminate/http: ^11.0|^12.0
- illuminate/routing: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0
- pestphp/pest: ^2.0|^3.0
README
Header-based API versioning with version flags for Laravel. Supports semantic versioning and feature flag-like version control.
Features
- 🏷️ Header-based versioning - Uses
X-API-Versionheader (industry standard like Stripe, GitHub) - 📦 Semantic versioning - Full support for major.minor.patch format (1.0.0, 1.1.0, 2.0.0)
- 🚩 Version flags - Enable/disable versions independently (perfect for app store review periods)
- 🔒 Minimum version middleware - Require minimum version per route:
min.version:1.1.0 - 🔄 Controller inheritance - Override only changed methods in versioned controllers
- 📱 Mobile-friendly - Disabled versions return
version_enabled: falseso apps can hide features - 🌍 Translations - Built-in support for English, Japanese, and Korean
Installation
composer require jeromejhipolito/laravel-api-versioning
Publish Configuration (Optional)
php artisan vendor:publish --tag=api-versioning-config php artisan vendor:publish --tag=api-versioning-lang
Configuration
Add to your .env:
# Optional: Comma-separated list of enabled versions (null = all enabled) API_ENABLED_VERSIONS=1.0.0,1.1.0 # Optional: Default version when header is missing API_DEFAULT_VERSION=1.0.0
Edit config/api-versioning.php:
return [ 'supported_versions' => ['1.0.0', '1.1.0', '2.0.0'], 'enabled_versions' => env('API_ENABLED_VERSIONS') ? array_map('trim', explode(',', env('API_ENABLED_VERSIONS'))) : null, // null = all supported versions enabled 'default_version' => env('API_DEFAULT_VERSION', '1.0.0'), ];
Register Middleware
In bootstrap/app.php:
use JeromeJHipolito\ApiVersioning\Middleware\ApiVersionMiddleware; use JeromeJHipolito\ApiVersioning\Middleware\ResolveVersionedController; ->withMiddleware(function (Middleware $middleware) { $middleware->api(append: [ ApiVersionMiddleware::class, ResolveVersionedController::class, ]); })
Usage
Making Requests
# With version header curl -H "X-API-Version: 1.0.0" https://api.example.com/users # Without header (uses default version) curl https://api.example.com/users
Response Headers
Every response includes:
X-API-Version: 1.0.0X-API-Version-Enabled: trueX-API-Supported-Versions: 1.0.0, 1.1.0, 2.0.0X-API-Enabled-Versions: 1.0.0, 1.1.0
Check Version Status
GET /api/version/status
{
"status": "success",
"data": {
"current_version": "1.0.0",
"version_enabled": true,
"default_version": "1.0.0",
"supported_versions": ["1.0.0", "1.1.0", "2.0.0"],
"enabled_versions": ["1.0.0", "1.1.0"],
"version_flags": {
"1.0.0": true,
"1.1.0": true,
"2.0.0": false
}
}
}
Using in Controllers
use JeromeJHipolito\ApiVersioning\Traits\VersionAwareTrait; class UserController extends Controller { use VersionAwareTrait; public function show($id) { $user = User::find($id); // Check version if ($this->isVersionAtLeast('2.0.0')) { return new V2\UserResource($user); } return new UserResource($user); } }
Using in Resources
use JeromeJHipolito\ApiVersioning\Traits\VersionAwareResourceTrait; class UserResource extends JsonResource { use VersionAwareResourceTrait; public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, // Only in 1.1.0+ ...$this->mergeWhenVersion('1.1.0', [ 'profile_score' => $this->profile_score, ]), // Only below 2.0.0 (deprecated) ...$this->mergeWhenVersionBelow('2.0.0', [ 'legacy_field' => $this->old_data, ]), ]; } }
Disabled Version Response
When a version is supported but not enabled:
{
"status": "success",
"version_enabled": false,
"message": "This API version is currently disabled...",
"current_version": "2.0.0",
"data": null
}
This allows mobile apps to check version_enabled and hide features accordingly.
Version Flags Workflow
-
Add new version as supported but disabled
'supported_versions' => ['1.0.0', '2.0.0'],
API_ENABLED_VERSIONS=1.0.0
-
Deploy to production - Old apps continue working
-
Submit new app version - App checks
version_flagsand hides 2.0.0 features -
After app store approval - Enable the version
API_ENABLED_VERSIONS=1.0.0,2.0.0
Minimum Version Middleware
Require a minimum API version for specific routes or groups:
Register the Middleware Alias
In bootstrap/app.php:
use JeromeJHipolito\ApiVersioning\Middleware\MinimumVersionMiddleware; ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'min.version' => MinimumVersionMiddleware::class, ]); })
Usage
// Single route Route::post('new-feature', [FeatureController::class, 'store']) ->middleware('min.version:1.1.0'); // Route group Route::group(['middleware' => ['min.version:2.0.0']], function () { Route::post('advanced', [AdvancedController::class, 'store']); Route::delete('advanced/{id}', [AdvancedController::class, 'destroy']); });
Response When Version Is Too Low
{
"message": "This endpoint requires API version 1.1.0 or higher",
"current_version": "1.0.0",
"minimum_version": "1.1.0"
}
HTTP Status: 400 Bad Request
Available Methods
VersionAwareTrait (Controllers)
| Method | Description |
|---|---|
getApiVersion() |
Get current version string |
getApiMajorVersion() |
Get major version number |
getApiMinorVersion() |
Get minor version number |
getApiPatchVersion() |
Get patch version number |
isVersionAtLeast($v) |
Check if >= version |
isVersionBelow($v) |
Check if < version |
isVersionExactly($v) |
Check if exact version |
isVersionBetween($min, $max) |
Check if in range |
VersionAwareResourceTrait (Resources)
| Method | Description |
|---|---|
mergeWhenVersion($v, $array) |
Merge array if >= version |
mergeWhenVersionBelow($v, $array) |
Merge array if < version |
mergeWhenVersionExactly($v, $array) |
Merge array if exact version |
mergeWhenVersionBetween($min, $max, $array) |
Merge if in range |
whenVersion($v, $value, $default) |
Return value if >= version |
whenVersionBelow($v, $value, $default) |
Return value if < version |
License
MIT License. See LICENSE for details.