API evrimi kaçınılmazdır. Uygulamanız büyüdükçe, eski uç noktaları (endpoints) kaldırmanız gerekecek, ancak geriye dönük uyumluluğu korumak önemlidir. Peki, bir uç noktanın yalnızca bir HTTP metodunu (örn. GET) kullanımdan kaldırırken diğerlerini nasıl aktif tutabilirsiniz?
<p>Bu yazıda, aynı rotada (route) POST isteğini aktif tutarken GET isteğini kullanımdan kaldırmanın yaygın bir senaryosunu nasıl ele alabileceğinizi göstereceğim.</p>
<p><strong>Problem</strong></p>
<p>Örneğin, aşağıdaki gibi bir rota tanımınız olduğunu düşünün:</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// modules/Products/Routes/api.php
Route::get(‘/products/{id}/export’, ProductExportController::class)->name(‘export’);
Route::post(‘/products/{id}/export’, ProductExportController::class)->name(‘export’);
<p>Her iki rota da aynı controller'ı kullanıyor, fakat GET metodunu kaldırmak istiyorsunuz. Controller'a ekleyeceğiniz kullanım dışı bırakma başlıkları (deprecation headers) her iki metodun da etkilenmesine yol açacaktır.</p>
<p><strong>Neden Doğru Kullanımdan Kaldırma Önemlidir</strong></p>
<p>Çözüm önerilerine geçmeden önce, bunu neden dikkate almanız gerektiğini anlamak önemlidir:</p>
<ol>
<li>
<strong>Client İletişimi</strong>: Tüketicilerin geçiş yapmaları için önceden bildirim alması gerekebilir.</li>
<li>
<strong>Standartlara Uygunluk</strong>: HTTP için kullanım dışı bırakma (Deprecation) ve güneş batışı (Sunset) başlıkları standarttır.</li>
<li>
<strong>İzleme</strong>: Hâlâ kullanım dışı bırakılmış uç noktaları kullanan istemcileri takip etme olanağı sağlar.</li>
<li>
<strong>Nazik Geçiş</strong>: Üretim sistemlerini bozmayı önler.</li>
</ol>
<h2>
<a name="solution-1-separate-legacy-controller-recommended" href="#solution-1-separate-legacy-controller-recommended">
</a>
Çözüm 1: Ayrı Bir Eski Controller Oluşturma (Önerilir)
</h2>
<p>En temiz yaklaşım, kullanım dışı bırakılan uç nokta için özel bir controller oluşturmaktır. Bu controller, ana controller'a yönlendirme yaparken kullanım dışı bırakma başlıklarını ekler.</p>
<h3>
<a name="step-1-create-the-legacy-controller" href="#step-1-create-the-legacy-controller">
</a>
Adım 1: Eski Controller'ı Oluşturun
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// app/Http/Controllers/ProductExportLegacyController.php
<?php namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProductExportLegacyController
{
public function __invoke(Request $request, $id)
{
// Ana controller’a yönlendirme yap
$response = app(ProductExportController::class)($request, $id);
// Kullanım dışı bırakma başlıklarını ekleyin
return $response
->header('Deprecation', 'true')
->header('Sunset', 'Sat, 01 Jun 2026 00:00:00 GMT')
->header('X-API-Warn', 'Bu uç nokta kullanım dışıdır. Yerine POST /products/{id}/export kullanın.');
}}
<h3>
<a name="step-2-update-your-routes" href="#step-2-update-your-routes">
</a>
Adım 2: Rotalarınızı Güncelleyin
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// Kullanım dışı bırakılan GET uç noktası
Route::get(‘/products/{id}/export’, ProductExportLegacyController::class)
->name(‘exportLegacy’); // KULLANIM DIŞI – Bunun yerine POST kullanın
// Aktif POST uç noktası
Route::post(‘/products/{id}/export’, ProductExportController::class)
->name(‘export’);
<p><strong>Avantajlar</strong></p>
<ul>
<li>✅ Net sorumluluk ayrımı</li>
<li>✅ Kullanım dışı bırakma süresi sona erdiğinde kolaylıkla kaldırılabilir</li>
<li>✅ Ana controller'da koşullu mantık yok</li>
<li>✅ Kendini belgelendiren kod</li>
</ul>
<h2>
<a name="solution-2-methodaware-middleware" href="#solution-2-methodaware-middleware">
</a>
Çözüm 2: Metod-Tabanlı Middleware
</h2>
<p>Middleware tercih ederseniz, başlıkları eklemeden önce HTTP metodunu kontrol eden bir middleware oluşturabilirsiniz.</p>
<h3>
<a name="step-1-create-the-middleware" href="#step-1-create-the-middleware">
</a>
Adım 1: Middleware'yi Oluşturun
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>php artisan make:middleware DeprecateGetMethod
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// app/Http/Middleware/DeprecateGetMethod.php
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class DeprecateGetMethod
{
public function handle(Request $request, Closure $next, ?string $sunset = null, ?string $message = null)
{
$response = $next($request);
if ($request->isMethod('GET')) {
$response->headers->set('Deprecation', 'true');
$response->headers->set('Sunset', $sunset ?? now()->addMonths(6)->toRfc7231String());
if ($message) {
$response->headers->set('X-API-Warn', $message);
}
}
return $response;
}}
<h3>
<a name="step-2-register-the-middleware" href="#step-2-register-the-middleware">
</a>
Adım 2: Middleware'yi Kayıt Ettirin
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// bootstrap/app.php veya app/Http/Kernel.php
protected $middlewareAliases = [
// … diğer middleware’ler
‘deprecate.get’ => \App\Http\Middleware\DeprecateGetMethod::class,
];
<h3>
<a name="step-3-apply-to-route" href="#step-3-apply-to-route">
</a>
Adım 3: Rotaya Uygulayın
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>Route::get(‘/products/{id}/export’, ProductExportController::class)
->name(‘exportLegacy’)
->middleware(‘deprecate.get:2026-06-01, Bunun yerine POST metodunu kullanın’);
Route::post(‘/products/{id}/export’, ProductExportController::class)
->name(‘export’);
<p><strong>Avantajlar</strong></p>
<ul>
<li>✅ Birden fazla rotada yeniden kullanılabilir</li>
<li>✅ Parametreli kapanış tarihi ve mesajı</li>
<li>✅ Temiz rota tanımlamaları</li>
</ul>
<h2>
<a name="solution-3-generic-deprecation-middleware" href="#solution-3-generic-deprecation-middleware">
</a>
Çözüm 3: Genel Kullanım Dışı Bırakma Middleware'i
</h2>
<p>Maksimum esneklik için, herhangi bir HTTP metoduyla çalışan bir middleware oluşturun.</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// app/Http/Middleware/DeprecateEndpoint.php
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class DeprecateEndpoint
{
public function handle(Request $request, Closure $next, ?string $methods = null, ?string $sunset = null, ?string $replacement = null)
{
$response = $next($request);
// Eğer hiçbir metod belirtilmemişse, tümünü kullanım dışı bırak
// Eğer metodlar belirtilmişse, sadece o metodları kullanım dışı bırak
$deprecatedMethods = $methods ? explode(',', strtoupper($methods)) : ['*'];
if ($deprecatedMethods === ['*'] || in_array($request->method(), $deprecatedMethods)) {
$response->headers->set('Deprecation', 'true');
$response->headers->set('Sunset', $sunset ?? now()->addMonths(6)->toRfc7231String());
if ($replacement) {
$response->headers->set('Link', "; rel=\"alternate\"");
}
}
return $response;
}}
<p>Kullanım:<br/></p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>// Sadece GET ve DELETE metodlarını kaldır
Route::match([‘get’, ‘delete’], ‘/products/{id}/export’, ProductExportController::class)
->middleware(‘deprecated:GET|DELETE,2026-06-01,/api/v2/products/{id}/export’);
<p><strong>Kullanım Dışı Bırakma Başlıklarını Anlamak</strong></p>
<p>Kullandığımız HTTP başlıklarını aşağıda inceleyelim:</p>
<p><strong>Deprecation: true</strong></p>
<p><strong>Sunset:</strong></p>
<p><strong>X-API-Warn:</strong></p>
<ul>
<li>Standart: Özel (yaygın uygulama)</li>
<li>Amacı: İnsan okuyuculu bir kullanım dışı bırakma mesajı</li>
<li>İstemci Eylemi: Geliştiricilere görüntüle</li>
</ul>
<p><strong>Link: ; rel="alternate"</strong></p>
<h2>
<a name="best-practices" href="#best-practices">
</a>
En İyi Uygulamalar
</h2>
<h3>
<a name="1-document-everywhere" href="#1-document-everywhere">
</a>
1. Her Yerde Belgeleyin
</h3>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>/
@deprecated Bu GET uç noktası v2.5.0 itibarıyla geçersizdir.
v3.0.0 (Haziran 2026) tarihinde kaldırılacaktır.
Bunun yerine POST /products/{id}/export kullanın.
*/
Route::get(‘/products/{id}/export’, ProductExportLegacyController::class)
->name(‘exportLegacy’);
2. Kullanım Dışı Kalanları KaydedinHâlâ kullanım dışı bırakılan uç noktaları kullananları takip edin:
public function __invoke(Request $request, $id) { Log::warning('Kullanım dışı bırakılmış GET /products/export uç noktası kullanıldı', [ 'product_id' => $id, 'client_ip' => $request->ip(), 'user_agent' => $request->userAgent(), ]);// ... controller'ın geri kalanı }
3. Değişikliği İletin- API belgelerinizi güncelleyin
- API tüketicilerine e-posta bildirimleri gönderin
- Değişiklik kayıtlarına ekleme yapın
- OpenAPI/Swagger spesifikasyonlarını güncelleyin
4. Gerçekçi Güneş Batışı Tarihleri BelirleyinMüşterilere geçiş için yeterince süre verin:
- Küçük değişiklikler: 3-6 ay
- Büyük değişiklikler: 6-12 ay
- Kırılma değişiklikleri: 12+ ay
5. API’nizi VersiyonlayınBüyük değişiklikler için versiyonlu rotaları göz önünde bulundurun:
// Eski versiyon (kullanım dışı) Route::prefix('v1')->group(function () { Route::get('/products/{id}/export', ProductExportLegacyController::class); });// Yeni versiyon Route::prefix('v2')->group(function () { Route::post('/products/{id}/export', ProductExportController::class); });
<h2> <a name="monitoring-deprecated-endpoints" href="#monitoring-deprecated-endpoints"> </a> Kullanım Dışı Bırakılan Uç Noktaları İzleme </h2> <p>Basit bir izleme sistemi oluşturun:<br/></p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// app/Http/Middleware/TrackDeprecatedUsage.php
public function handle(Request $request, Closure $next)
{
$response = $next($request);if ($response->headers->has('Deprecation')) { event(new DeprecatedEndpointAccessed( endpoint: $request->path(), method: $request->method(), user: $request->user(), ip: $request->ip(), )); } return $response;}
<p>Ardından, bir panel veya rapor oluşturun:<br/></p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>DB::table(‘deprecated_endpoint_usage’)
->select(‘endpoint’, DB::raw(‘count(*) as hits’))
->where(‘accessed_at’, ‘>’, now()->subDays(30))
->groupBy(‘endpoint’)
->get();<h2> <a name="the-removal-process" href="#the-removal-process"> </a> Kaldırma Süreci </h2> <p>Güneş batışı tarihi geldiğinde:</p> <h3> <a name="1-final-warning-period-12-weeks-before" href="#1-final-warning-period-12-weeks-before"> </a> 1. Son Uyarı Dönemi (2-1 hafta önce) </h3> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>public function __invoke(Request $request, $id)
{
Log::critical(‘SON UYARI: Kullanım dışı bırakılmış uç nokta 2 hafta içinde kaldırılacak’, [
‘endpoint’ => $request->path(),
‘removal_date’ => ‘2026-06-01’,
]);// ... controller'ın geri kalanı}
<h3> <a name="2-graceful-removal" href="#2-graceful-removal"> </a> 2. Nazik Kaldırma </h3> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>// 404 Not Found yerine 410 Gone döndürün
Route::get(‘/products/{id}/export’, function () {
return response()->json([
‘message’ => ‘Bu uç nokta 1 Haziran 2026 tarihinde kaldırılmıştır’,
‘replacement’ => ‘POST /products/{id}/export’,
‘documentation’ => ‘https://docs.example.com/api/v2/products‘,
], 410);
}) ->name(‘exportRemoved’);<h3> <a name="3-complete-removal" href="#3-complete-removal"> </a> 3. Tam Kaldırma </h3> <p>Bir nazik geçiş süresinden (örneğin, 3-6 ay) sonra, rotayı tamamen kaldırın.</p> <h2> <a name="conclusion" href="#conclusion"> </a> Sonuç </h2> <p>Belli HTTP metodlarını ortak uç noktalarda kullanım dışı bırakmak, düşünceli bir uygulama gerektirir. Ayrı controller yaklaşımı, netlik ve sürdürülebilirlik açısından en iyi dengeyi sağlar, middleware çözümleri ise API'niz boyunca yeniden kullanılabilirlik sunar.</p> <p>Unutmayın:<br/>✅ Standart HTTP başlıklarını kullanın<br/>✅ Açık geçiş yolları sağlayın<br/>✅ Yeterli ön bildirim verin<br/>✅ Kullanımı izleyin<br/>✅ Her şeyi belgeleyin</p> <p>API tüketicileri, geçişin sorunsuz olması için size teşekkür edecek!</p>Kaynak: Orijinal Makale


