feat(api): allow deprecation without sunset date
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
691ef936d4
commit
93cdb62dfe
4 changed files with 90 additions and 15 deletions
|
|
@ -40,6 +40,14 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
* Route::middleware('api.sunset:2025-06-01,/api/v2/new-endpoint')->group(function () {
|
||||
* Route::get('/old-endpoint', OldController::class);
|
||||
* });
|
||||
*
|
||||
* You can also mark a route as deprecated without a fixed removal date:
|
||||
*
|
||||
* ```php
|
||||
* Route::middleware('api.sunset')->group(function () {
|
||||
* Route::get('/old-endpoint', OldController::class);
|
||||
* });
|
||||
* ```
|
||||
* ```
|
||||
*
|
||||
* ## Response Headers
|
||||
|
|
@ -56,29 +64,31 @@ class ApiSunset
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param string $sunsetDate The sunset date (YYYY-MM-DD or RFC7231 format)
|
||||
* @param string $sunsetDate The sunset date (YYYY-MM-DD or RFC7231 format), or empty for deprecation-only
|
||||
* @param string|null $replacement Optional replacement endpoint URL
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string $sunsetDate, ?string $replacement = null): Response
|
||||
public function handle(Request $request, Closure $next, string $sunsetDate = '', ?string $replacement = null): Response
|
||||
{
|
||||
/** @var Response $response */
|
||||
$response = $next($request);
|
||||
|
||||
// Convert date to RFC7231 format if needed
|
||||
$formattedDate = $this->formatSunsetDate($sunsetDate);
|
||||
if ($sunsetDate !== '') {
|
||||
// Convert date to RFC7231 format if needed
|
||||
$formattedDate = $this->formatSunsetDate($sunsetDate);
|
||||
|
||||
// Add Sunset header
|
||||
$response->headers->set('Sunset', $formattedDate);
|
||||
// Add Sunset header
|
||||
$response->headers->set('Sunset', $formattedDate);
|
||||
}
|
||||
|
||||
// Add Deprecation header
|
||||
$response->headers->set('Deprecation', 'true');
|
||||
|
||||
// Add warning header
|
||||
$version = $request->attributes->get('api_version', 'unknown');
|
||||
$response->headers->set(
|
||||
'X-API-Warn',
|
||||
"This endpoint is deprecated and will be removed on {$sunsetDate}."
|
||||
);
|
||||
$warning = 'This endpoint is deprecated.';
|
||||
if ($sunsetDate !== '') {
|
||||
$warning = "This endpoint is deprecated and will be removed on {$sunsetDate}.";
|
||||
}
|
||||
$response->headers->set('X-API-Warn', $warning);
|
||||
|
||||
// Add Link header for replacement if provided
|
||||
if ($replacement !== null) {
|
||||
|
|
|
|||
|
|
@ -246,11 +246,17 @@ class VersionedRoutes
|
|||
{
|
||||
$middleware = ["api.version:{$this->version}"];
|
||||
|
||||
if ($this->isDeprecated && $this->sunsetDate) {
|
||||
if ($this->replacement !== null && $this->replacement !== '') {
|
||||
$middleware[] = "api.sunset:{$this->sunsetDate},{$this->replacement}";
|
||||
if ($this->isDeprecated) {
|
||||
if ($this->sunsetDate !== null && $this->sunsetDate !== '') {
|
||||
if ($this->replacement !== null && $this->replacement !== '') {
|
||||
$middleware[] = "api.sunset:{$this->sunsetDate},{$this->replacement}";
|
||||
} else {
|
||||
$middleware[] = "api.sunset:{$this->sunsetDate}";
|
||||
}
|
||||
} elseif ($this->replacement !== null && $this->replacement !== '') {
|
||||
$middleware[] = "api.sunset:,$this->replacement";
|
||||
} else {
|
||||
$middleware[] = "api.sunset:{$this->sunsetDate}";
|
||||
$middleware[] = 'api.sunset';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
31
src/php/tests/Feature/ApiSunsetTest.php
Normal file
31
src/php/tests/Feature/ApiSunsetTest.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Core\Front\Api\Middleware\ApiSunset;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
it('adds deprecation headers without a sunset date', function () {
|
||||
$middleware = new ApiSunset();
|
||||
$request = Request::create('/legacy-endpoint', 'GET');
|
||||
|
||||
$response = $middleware->handle($request, fn () => new Response('OK'));
|
||||
|
||||
expect($response->headers->get('Deprecation'))->toBe('true');
|
||||
expect($response->headers->has('Sunset'))->toBeFalse();
|
||||
expect($response->headers->has('Link'))->toBeFalse();
|
||||
expect($response->headers->get('X-API-Warn'))->toBe('This endpoint is deprecated.');
|
||||
});
|
||||
|
||||
it('adds a replacement link without a sunset date', function () {
|
||||
$middleware = new ApiSunset();
|
||||
$request = Request::create('/old-endpoint', 'GET');
|
||||
|
||||
$response = $middleware->handle($request, fn () => new Response('OK'), '', '/api/v4/users');
|
||||
|
||||
expect($response->headers->get('Deprecation'))->toBe('true');
|
||||
expect($response->headers->has('Sunset'))->toBeFalse();
|
||||
expect($response->headers->get('Link'))->toBe('</api/v4/users>; rel="successor-version"');
|
||||
expect($response->headers->get('X-API-Warn'))->toBe('This endpoint is deprecated.');
|
||||
});
|
||||
|
|
@ -32,3 +32,31 @@ it('preserves the existing deprecated signature without a replacement url', func
|
|||
expect($attributes['middleware'])->toContain('api.sunset:2025-06-01');
|
||||
expect($attributes['middleware'])->not->toContain('api.sunset:2025-06-01,/api/v3/users');
|
||||
});
|
||||
|
||||
it('keeps deprecated routes active without a sunset date', function () {
|
||||
$routes = new class (3) extends VersionedRoutes {
|
||||
public function attributes(): array
|
||||
{
|
||||
return $this->buildRouteAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
$attributes = $routes->deprecated()->attributes();
|
||||
|
||||
expect($attributes['middleware'])->toContain('api.version:3');
|
||||
expect($attributes['middleware'])->toContain('api.sunset');
|
||||
});
|
||||
|
||||
it('passes a replacement url through deprecated versioned routes without a sunset date', function () {
|
||||
$routes = new class (4) extends VersionedRoutes {
|
||||
public function attributes(): array
|
||||
{
|
||||
return $this->buildRouteAttributes();
|
||||
}
|
||||
};
|
||||
|
||||
$attributes = $routes->deprecated(null, '/api/v4/users')->attributes();
|
||||
|
||||
expect($attributes['middleware'])->toContain('api.version:4');
|
||||
expect($attributes['middleware'])->toContain('api.sunset:,/api/v4/users');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue