Skip to content

Version Declaration

Jean-Marc Strauven edited this page Dec 23, 2025 · 2 revisions

Version Declaration

Learn how to declare and configure API versions using the fluent API.


Basic Declaration

Define versions in routes/api.php:

use Grazulex\ApiRoute\Facades\ApiRoute;
use Illuminate\Support\Facades\Route;

ApiRoute::version('v1', function () {
    Route::get('users', [UserController::class, 'index']);
    Route::post('users', [UserController::class, 'store']);
});

Fluent API

The version() method returns a VersionDefinition object with a fluent API:

Mark as Current

Set the version as the current stable version:

ApiRoute::version('v2', function () {
    Route::apiResource('users', UserController::class);
})->current();

Mark as Beta

Set the version as beta/preview:

ApiRoute::version('v3', function () {
    Route::apiResource('users', UserController::class);
})->beta();

Set Deprecation Date

Mark the version as deprecated with a date:

ApiRoute::version('v1', function () {
    Route::apiResource('users', UserController::class);
})->deprecated('2025-06-01');

You can also use Carbon:

use Carbon\Carbon;

ApiRoute::version('v1', function () {
    // ...
})->deprecated(Carbon::parse('2025-06-01'));

Set Sunset Date

Set the end-of-life date for a version:

ApiRoute::version('v1', function () {
    Route::apiResource('users', UserController::class);
})
->deprecated('2025-06-01')
->sunset('2025-12-01');

Set Successor Version

Specify which version succeeds this one (for Link header):

ApiRoute::version('v1', function () {
    // ...
})
->deprecated('2025-06-01')
->sunset('2025-12-01')
->setSuccessor('v2');

Set Documentation URL

Add a documentation URL for the version:

ApiRoute::version('v1', function () {
    // ...
})->documentation('https://docs.example.com/api/v1');

Set Rate Limit

Apply version-specific rate limiting:

// Lower rate limit for deprecated version
ApiRoute::version('v1', function () {
    // ...
})
->deprecated('2025-06-01')
->rateLimit(100); // 100 requests/minute

// Higher rate limit for current version
ApiRoute::version('v2', function () {
    // ...
})
->current()
->rateLimit(1000); // 1000 requests/minute

Add Middleware

Add additional middleware to a version:

ApiRoute::version('v2', function () {
    // ...
})->middleware(['auth:sanctum', 'throttle:api']);

// Or single middleware
ApiRoute::version('v2', function () {
    // ...
})->middleware('auth:sanctum');

Set Route Name Prefix

Set a custom route name prefix:

ApiRoute::version('v2', function () {
    Route::get('users', [UserController::class, 'index'])->name('users.index');
})->name_('api.v2.');

// Route name becomes: api.v2.users.index

Complete Example

use Grazulex\ApiRoute\Facades\ApiRoute;
use Illuminate\Support\Facades\Route;

// Version 1 - Deprecated, will be sunset
ApiRoute::version('v1', function () {
    Route::apiResource('users', App\Http\Controllers\Api\V1\UserController::class);
    Route::apiResource('posts', App\Http\Controllers\Api\V1\PostController::class);
})
->deprecated('2025-06-01')
->sunset('2025-12-01')
->setSuccessor('v2')
->documentation('https://docs.myapp.com/api/v1')
->rateLimit(100);

// Version 2 - Current stable version
ApiRoute::version('v2', function () {
    Route::apiResource('users', App\Http\Controllers\Api\V2\UserController::class);
    Route::apiResource('posts', App\Http\Controllers\Api\V2\PostController::class);
    Route::apiResource('comments', App\Http\Controllers\Api\V2\CommentController::class);
})
->current()
->documentation('https://docs.myapp.com/api/v2')
->rateLimit(1000);

// Version 3 - Beta preview
ApiRoute::version('v3', function () {
    Route::apiResource('users', App\Http\Controllers\Api\V3\UserController::class);
})
->beta()
->documentation('https://docs.myapp.com/api/v3-beta')
->middleware(['auth:sanctum']);

VersionDefinition Methods

Setters (Fluent)

Method Description
current() Mark as current stable version
beta() Mark as beta/preview
deprecated(string|Carbon $date) Set deprecation date
sunset(string|Carbon $date) Set sunset date
setSuccessor(string $version) Set successor version
documentation(string $url) Set documentation URL
rateLimit(int $requests) Set rate limit per minute
middleware(array|string $middleware) Add middleware
name_(string $name) Set route name prefix

Getters

Method Return Description
name() string Get version name
routes() Closure Get routes closure
status() VersionStatus Get current status
deprecationDate() ?Carbon Get deprecation date
sunsetDate() ?Carbon Get sunset date
successor() ?string Get successor version
documentationUrl() ?string Get documentation URL
rateLimit_() ?int Get rate limit
middlewares() array|string Get middleware
routeName() ?string Get route name prefix

Status Checks

Method Return Description
isActive() bool Is status Active?
isBeta() bool Is status Beta?
isDeprecated() bool Is status Deprecated?
isSunset() bool Is sunset (past sunset date)?
isUsable() bool Can still be used?

Using the Facade

Access version information via the ApiRoute facade:

use Grazulex\ApiRoute\Facades\ApiRoute;

// Get all versions
$versions = ApiRoute::versions(); // Collection<VersionDefinition>

// Get specific version
$v1 = ApiRoute::getVersion('v1'); // ?VersionDefinition

// Get current version
$current = ApiRoute::currentVersion(); // ?VersionDefinition

// Check if version exists
if (ApiRoute::hasVersion('v2')) {
    // ...
}

// Status checks
ApiRoute::isDeprecated('v1'); // bool
ApiRoute::isSunset('v1');     // bool
ApiRoute::isActive('v2');     // bool

// Resolve version from request
$version = ApiRoute::resolveVersion(request()); // string

Version Status Enum

use Grazulex\ApiRoute\Support\VersionStatus;

enum VersionStatus: string
{
    case Active = 'active';
    case Beta = 'beta';
    case Deprecated = 'deprecated';
    case Sunset = 'sunset';
}

// Check if usable
$status->isUsable(); // true for Active, Beta, Deprecated

// Get label
$status->label(); // "Active", "Beta", etc.

Next Steps

Clone this wiki locally