01.02.2026

Laravel’de API Versiyonlama Stratejisi: Kırmadan Evrimleştirmek (v1’den v2’ye)

Laravel’de API versiyonlamayı URL/Header ile kurgula; deprecate süreci, transformer’lar ve testlerle kırmadan ilerle.

API’ler “bitmiş ürün” değil; canlı bir sözleşmedir. Yeni alan eklemek kolay, ama alan adı değiştirmek veya davranışı düzeltmek çoğu zaman kırıcı (breaking) etki yapar. Laravel’de API versiyonlamayı doğru kurgulamak; hem hızlı evrim hem de geriye dönük uyumluluk demektir.

1) Versiyonlama ne zaman gerçekten gerekli?

Her değişiklikte v2 çıkarmak yerine şunu ayır:

  • Geriye uyumlu: Yeni alan eklemek, opsiyonel parametre eklemek, yeni endpoint eklemek.
  • Kırıcı: Alan adı/format değişikliği (string → object), zorunlu alan eklemek, HTTP status/iş kuralı değişimi.

Kırıcı değişiklik varsa versiyon devreye girsin; diğerlerinde tek versiyonda ilerlemek genelde yeterlidir.

2) URL tabanlı versiyonlama (kolay ve görünür)

En pratik yaklaşım: /api/v1/... ve /api/v2/....

routes/api.php

Route::prefix('v1')->group(function () {
    Route::get('orders/{order}', [\App\Http\Controllers\Api\V1\OrderController::class, 'show']);
});

Route::prefix('v2')->group(function () {
    Route::get('orders/{order}', [\App\Http\Controllers\Api\V2\OrderController::class, 'show']);
});

Artısı: Dokümantasyon ve debug kolay. Eksisi: URL’ler çoğalır; ama yönetilebilir.

3) Header tabanlı versiyonlama (aynı URL, farklı sözleşme)

Tek endpoint URL’si kullanıp versiyonu header’dan okuyabilirsin:

  • Accept: application/vnd.myapp.v2+json
  • veya X-Api-Version: 2

Bu yaklaşımda route tek kalır; içeride farklı “serializer/transformer” seçersin. Ek bir middleware ile versiyonu request’e yazabilirsin.

4) Controller kopyalamak yerine “Transformer” katmanı

Versiyonlar büyüdükçe controller’ları kopyalamak teknik borç üretir. Daha temiz çözüm: aynı domain verisini farklı şekilde sunan transformer’lar.

Örnek: v1’de total düz sayıydı, v2’de para formatı istiyorsun.

app/Http/Resources/V1/OrderResource.php

class OrderResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'total' => $this->total_cents / 100,
        ];
    }
}

app/Http/Resources/V2/OrderResource.php

class OrderResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'total' => [
                'amount' => $this->total_cents,
                'currency' => 'TRY',
            ],
        ];
    }
}

Controller sadece doğru resource’u seçer:

public function show(Order $order)
{
    return new \App\Http\Resources\V2\OrderResource($order);
}

Bu sayede domain modeli aynı kalır, “sözleşme” katmanı versiyonlanır.

5) Deprecation (kaldırma) planı: Sürpriz yok

Versiyonlamanın yarısı iletişimdir.

  • Response header ekle:
    • Deprecation: true
    • Sunset: Wed, 30 Apr 2026 00:00:00 GMT
  • JSON body’ye kırıcı mesaj ekleme (client’ları parse ederken riskli olabilir). Header daha güvenli.

Laravel’de basit bir middleware ile v1 isteklerine bu header’ları ekleyebilirsin.

6) Sözleşme testleri: Versiyonlar “yan yana” yaşamalı

İki versiyonu aynı anda taşırken en kritik nokta: v1’i düzeltirken v2’yi, v2’yi geliştirirken v1’i bozmamak.

Pratik yaklaşım:

  • Her versiyon için ayrı feature test klasörü: tests/Feature/Api/V1 ve V2.
  • Aynı seed ile aynı order için farklı response bekle.

Örnek assertion:

$this->getJson('/api/v1/orders/1')
    ->assertOk()
    ->assertJsonStructure(['id', 'total']);

$this->getJson('/api/v2/orders/1')
    ->assertOk()
    ->assertJsonStructure(['id', 'total' => ['amount', 'currency']]);

Sonuç

Laravel’de API versiyonlama; route prefix’leri, Resource/Transformer katmanı ve net bir deprecation takvimiyle sürdürülebilir hale gelir. Amaç “v2 çıkarıp unutmak” değil; sözleşmeyi kontrollü biçimde evrimleştirmektir.