shahghasiadil / laravel-api-versioning
Elegant attribute-based API versioning solution for Laravel applications with built-in deprecation management and version inheritance
Package info
github.com/shahghasiadil/laravel-api-versioning
pkg:composer/shahghasiadil/laravel-api-versioning
Fund package maintenance!
Requires
- php: ^8.2
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.14
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.34|^3.0
- pestphp/pest-plugin-laravel: ^2.4|^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1||^2.0
- phpstan/phpstan-phpunit: ^1.3||^2.0
- phpstan/phpstan-strict-rules: ^1.5||^2.0
This package is auto-updated.
Last update: 2026-03-30 10:20:33 UTC
README
Attribute-based API versioning for Laravel, with version detection, deprecation metadata, versioned resources, and route inspection commands.
Requirements
- PHP 8.2+
- Laravel 10, 11, or 12
Installation
You can install the package via composer:
composer require shahghasiadil/laravel-api-versioning
Publish the config file:
php artisan vendor:publish --provider="ShahGhasiAdil\LaravelApiVersioning\ApiVersioningServiceProvider" --tag="config"
Quick Start
1. Configure supported versions
Edit config/api-versioning.php:
return [ 'default_version' => '2.0', 'supported_versions' => ['1.0', '1.1', '2.0', '2.1'], 'detection_methods' => [ 'header' => ['enabled' => true, 'header_name' => 'X-API-Version'], 'query' => ['enabled' => true, 'parameter_name' => 'api-version'], 'path' => ['enabled' => true, 'prefix' => 'api/v'], 'media_type' => ['enabled' => false, 'format' => 'application/vnd.api+json;version=%s'], ], ];
2. Apply middleware to API routes
api.version middleware alias is registered by the package.
use Illuminate\Support\Facades\Route; Route::middleware('api.version')->group(function () { Route::apiResource('users', UserController::class); });
3. Add version attributes to your controller
use ShahGhasiAdil\LaravelApiVersioning\Attributes\ApiVersion; use ShahGhasiAdil\LaravelApiVersioning\Attributes\Deprecated; use ShahGhasiAdil\LaravelApiVersioning\Attributes\MapToApiVersion; use ShahGhasiAdil\LaravelApiVersioning\Traits\HasApiVersionAttributes; #[ApiVersion(['2.0', '2.1'])] class UserController extends Controller { use HasApiVersionAttributes; public function index(): JsonResponse { return response()->json([ 'version' => $this->getCurrentApiVersion(), 'deprecated' => $this->isVersionDeprecated(), ]); } #[MapToApiVersion(['2.1'])] public function store(Request $request): JsonResponse { return response()->json(['message' => 'Created']); } #[MapToApiVersion(['2.0'])] #[Deprecated(message: 'Use store() instead', replacedBy: '2.1', sunsetDate: '2026-12-31')] public function create(Request $request): JsonResponse { return response()->json(['message' => 'Deprecated endpoint']); } }
4. Call your API with a version
# Header curl -H "X-API-Version: 2.0" https://api.example.com/api/users # Query string curl "https://api.example.com/api/users?api-version=2.0" # Path-based curl https://api.example.com/api/v2.0/users # Media type curl -H "Accept: application/vnd.api+json;version=2.0" https://api.example.com/api/users
Features
- Controller and method level attributes (
ApiVersion,MapToApiVersion) - Version-neutral endpoints (
ApiVersionNeutral) - Deprecation metadata (
Deprecatedwith message, sunset date, replacement) - Multiple version detection methods (header, query, path, media type)
- Response headers for active/supported/deprecated versions
- Version-aware resources and resource collections
- Version inheritance and method mapping for resources
- RFC 7807 problem+json error responses for unsupported versions
- Built-in version comparison utilities
- Cache layer for attribute resolution
- Artisan commands for generation, inspection, config and health checks
- Testing base class with version request/assert helpers
Attributes
ApiVersion
Use on a controller or method.
#[ApiVersion('2.0')] #[ApiVersion(['1.0', '1.1', '2.0'])]
MapToApiVersion
Use on a method to map it to specific versions.
#[MapToApiVersion(['2.0', '2.1'])]
ApiVersionNeutral
Marks controller/method as version-neutral (available in all supported versions).
use ShahGhasiAdil\LaravelApiVersioning\Attributes\ApiVersionNeutral; #[ApiVersionNeutral] class HealthController extends Controller { // ... }
Deprecated
Add deprecation metadata to controller/method.
#[Deprecated(
message: 'Use v2 endpoint',
sunsetDate: '2026-12-31',
replacedBy: '2.0'
)]
Response Headers
When middleware is active, responses can include:
X-API-Version: 2.0 X-API-Supported-Versions: 1.0, 1.1, 2.0, 2.1 X-API-Route-Versions: 2.0, 2.1 X-API-Deprecated: true X-API-Deprecation-Message: Use store() instead X-API-Sunset: 2026-12-31 X-API-Replaced-By: 2.1
Versioned Resources
VersionedJsonResource
Extend VersionedJsonResource and implement toArrayDefault().
Then optionally add version-specific methods (toArrayV1, toArrayV11, toArrayV2, toArrayV21) or custom mappings via config.
use Illuminate\Http\Request; use ShahGhasiAdil\LaravelApiVersioning\Http\Resources\VersionedJsonResource; class UserResource extends VersionedJsonResource { protected function toArrayV1(Request $request): array { return ['id' => $this->id, 'name' => $this->name]; } protected function toArrayV2(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, ]; } protected function toArrayDefault(Request $request): array { return $this->toArrayV2($request); } }
VersionedResourceCollection
Extend VersionedResourceCollection for version-aware list payloads.
use Illuminate\Http\Request; use ShahGhasiAdil\LaravelApiVersioning\Http\Resources\VersionedResourceCollection; class UserCollection extends VersionedResourceCollection { protected function toArrayV1(Request $request): array { return ['data' => $this->collection]; } protected function toArrayV2(Request $request): array { return [ 'data' => $this->collection, 'meta' => ['count' => $this->collection->count()], ]; } protected function toArrayDefault(Request $request): array { return $this->toArrayV2($request); } }
Version Comparison Helpers
In controllers/resources using HasApiVersionAttributes:
getCurrentApiVersion()isVersionDeprecated()getDeprecationMessage()getSunsetDate()getReplacedByVersion()isVersionGreaterThan()isVersionGreaterThanOrEqual()isVersionLessThan()isVersionLessThanOrEqual()isVersionBetween()
Direct service usage:
use ShahGhasiAdil\LaravelApiVersioning\Services\VersionComparator; $comparator = app(VersionComparator::class); $comparator->isGreaterThan('2.0', '1.0'); $comparator->satisfies('2.1', '^2.0');
Error Format (RFC 7807)
Unsupported versions return application/problem+json:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "Unsupported API Version",
"status": 400,
"detail": "API version '3.0' is not supported for this endpoint.",
"requested_version": "3.0",
"supported_versions": ["1.0", "1.1", "2.0", "2.1"],
"endpoint_versions": ["2.0", "2.1"]
}
Optional documentation is included when api-versioning.documentation.base_url is set.
Artisan Commands
Generate controller stub with attributes:
php artisan make:versioned-controller UserController --api-version=2.0 php artisan make:versioned-controller V1UserController --api-version=1.0 --deprecated --sunset=2026-12-31 --replaced-by=2.0
Inspect routes and versions:
php artisan api:versions php artisan api:versions --route=users php artisan api:versions --api-version=2.0 php artisan api:versions --deprecated php artisan api:versions --compact php artisan api:versions --json
Check configuration health:
php artisan api:version:health
Show config overview:
php artisan api:version-config --show php artisan api:version-config --add-version=2.2 --method=toArrayV22
Clear attribute cache:
php artisan api:cache:clear
Testing Helpers
Use ShahGhasiAdil\LaravelApiVersioning\Testing\ApiVersionTestCase in package/app tests.
Available helpers include:
- Requests:
getWithVersion,getWithVersionQuery,postWithVersion,putWithVersion,deleteWithVersion - Assertions:
assertApiVersion,assertApiVersionDeprecated,assertApiVersionNotDeprecated,assertSupportedVersions,assertRouteVersions,assertDeprecationMessage,assertReplacedBy
Configuration Reference
Main file: config/api-versioning.php
return [ 'default_version' => '1.0', 'detection_methods' => [ 'header' => [ 'enabled' => true, 'header_name' => 'X-API-Version', ], 'query' => [ 'enabled' => true, 'parameter_name' => 'api-version', ], 'path' => [ 'enabled' => true, 'prefix' => 'api/v', ], 'media_type' => [ 'enabled' => false, 'format' => 'application/vnd.api+json;version=%s', ], ], 'supported_versions' => ['1.0', '1.1', '2.0', '2.1'], 'version_method_mapping' => [ '1.0' => 'toArrayV1', '1.1' => 'toArrayV11', '2.0' => 'toArrayV2', '2.1' => 'toArrayV21', ], 'version_inheritance' => [ '1.1' => '1.0', '2.1' => '2.0', ], 'default_method' => 'toArrayDefault', 'documentation' => [ 'base_url' => env('API_DOCUMENTATION_URL'), ], 'cache' => [ 'enabled' => env('API_VERSIONING_CACHE_ENABLED', true), 'ttl' => env('API_VERSIONING_CACHE_TTL', 3600), ], ];
Environment variables:
API_DOCUMENTATION_URL=https://docs.example.com/api API_VERSIONING_CACHE_ENABLED=true API_VERSIONING_CACHE_TTL=3600
Development
Run tests:
composer test
Run static analysis:
composer analyse
Format code:
composer format
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
If you discover any security-related issues, please email adil.shahghasi@gmail.com.
Credits
License
The MIT License (MIT). Please see LICENSE.md for details.