API Versioning Nedir? – Kısa Tanım ve Neden Önemli
API versioning, istemcilerin eski contract’ları bozulmadan yeni özellikleri tüketmesini sağlar. Ben bir üretim ERP’sinde yeni raporlama endpoint’i eklediğimde, eski entegrasyonların kırılmaması için versiyonlamayı zorunlu kıldım. Versiyonlama eksikliği yüzünden çok sayıda hata raporu aldığım ve ciddi ek bakım süresi harcadığım bir dönem yaşadım. Bu tür sıkıntılar, sadece client kodunda değil, log ve monitoring sistemlerinde de yankı bulur.
Burada iki ana yaklaşım var: URI‑based versioning ve Header‑based versioning. Her iki yöntemin de RFC 7231 (HTTP/1.1) içinde yeri var, ama pratikte hangisinin daha az sürüm yönetim karmaşası yarattığını görmek için gerçek bir senaryoya bakmak gerekiyor.
URI‑Based Versioning – Nasıl Çalışıyor?
URI‑based versioning, sürümü URL’de doğrudan belirtir:
GET /v1/orders?status=shipped
GET /v2/orders?status=shipped&include=customer
Ben bu yöntemi bir e‑ticaret platformunda uyguladığımda, birden fazla mikroservisin aynı anda farklı sürümlerini desteklemek zorunda kaldım. Bu, Nginx reverse proxy konfigürasyonunda aşağıdaki gibi bir map tanımı gerektirdi:
map $uri $backend {
~^/v1/ backend_v1;
~^/v2/ backend_v2;
}
Artıları
- Açık ve dokümante edilmesi basit: URL’ye bakarak hangi versiyonun çağrıldığını hemen görebiliyorum.
- Cache‑friendly: CDN’ler URL’yi anahtar olarak kullandığı için versiyon değişikliği cache miss’i oluşturur ve yeni yanıtlar alınır.
- Log analizinde rahatlık:
access.logsatırlarında/v2/gibi bir işaretle hangi sürümün ne kadar istek aldığını görebiliyorum.
Eksileri
- Yol uzaması: Çok sayıda endpoint ve sürüm olduğunda URL uzunluğu artar. Ben birden fazla endpoint’i
/v1/altında toplarken belirgin bir URL karmaşası yaşadım. - REST ilkeleriyle çelişme: Versiyonun bir “resource” gibi davranması, bazı purist REST tasarımcıları için itici olabilir.
Header‑Based Versioning – Nasıl Çalışıyor?
Header‑based versioning, sürüm bilgisini HTTP header’da taşır. Örneğin:
GET /orders?status=shipped HTTP/1.1
Accept: application/vnd.myapi.v2+json
Bu yöntemi bir üretim ERP’sinde devreye aldığımda, API Gateway (Kong) üzerinden bir plugin ile Accept header’ını parse ettim. Örnek Kong konfigürasyonu:
plugins:
- name: request-transformer
config:
add:
headers:
- "X-API-Version: 2"
Artıları
- URL temizliği: Versiyon bilgisi URL’de yer almadığı için endpoint’ler daha okunaklı olur (
/orderstek bir yer). - Versiyon geçişi daha esnek: Client’lar aynı URL’i tutarak
Acceptheader’ı değiştirir, bu da blue‑green deployment senaryolarında faydalı. - Mikroservisler arası ortaklaşa: Aynı gateway üzerinden farklı servislerin versiyonlarını tek bir header’da yönetebilirim.
Eksileri
- Cache uyumsuzluğu: CDN’ler genellikle URL’yi cache anahtarı olarak alır; header değişikliği cache miss’i yaratmaz, bu da eski yanıtların dağıtılmasına sebep olabilir.
- Dokümantasyon zorunluluğu: Client’ların doğru header’ı göndermesini sağlamak ekstra bir adım; ben bir iç API portalında Swagger UI üzerinden header eklemeyi zorunlu kıldığımda yine de azımsanmayacak sayıda “Missing Accept header” hatası aldım.
- Proxy ve firewall kısıtlamaları: Bazı kurumsal ağlar custom header’ları siler; bu durumda fallback stratejisi gerekir.
Karşılaştırma Tablosu – Hangisi Pratik?
| Özellik | URI‑Based | Header‑Based |
|---|---|---|
| Cache davranışı | URL değişince yeni cache, yüksek hit | Header değişince aynı cache, düşük hit |
| İstemci uyumluluğu | Çok geniş (tüm HTTP istemcileri) | İyi (bazı proxy/ firewall engeller) |
| Konfigürasyon karmaşıklığı | Nginx map + DNS |
API Gateway plugin + header mapping |
| Versiyon geçişi süresi | Görece uzun (URL değişikliği) | Görece kısa (header güncellemesi) |
| Dokümantasyon ihtiyacı | Basit (URL örnekleri) | Detaylı (Accept header formatı) |
Trade‑Off Analizi – Gerçek Dünya Kararları
Ben bir müşteri projesinde yeni bir “shipment tracking” API’si eklediğimde, iki sürüm arasında karar vermek zorunda kaldım. İlk denememde, URI‑based versiyonla /v1/tracking ve /v2/tracking endpoint’leri oluşturduğumda, iki farklı sürümün aynı anda çalıştığını fark ettim. Bu durum, log analizinde v1 ve v2 karışıklığına yol açtı; grep "v2" aramasıyla sadece yeni versiyonun hatalarını bulabildim.
Header‑based versiyona geçiş yapınca, aynı endpoint’i /tracking altında tutarak sadece Accept header’ını değiştirdim. Ancak CDN (Cloudflare) cache’i aynı kalınca, eski yanıtlar bir süre boyunca servis edildi. Bu sorunu, Cache‑Bypass query parametresi (?cb=timestamp) ekleyerek çözdüm; sonuçta cache hit oranı kabul edilebilir bir seviyeye geldi.
Edge‑Case’ler
- İç ağlarda header silinmesi: Bazı kurumsal ağlarda
Acceptgibi içerik header’ları proxy katmanında düşebiliyor. Çözüm: fallback olarakX-API-Versionheader’ı ekleyip gateway’de kontrol etmek. - Müşteri SDK’ları: Eski SDK’lar çoğunlukla yalnızca URL‑tabanlı versiyonlamayı destekler. Bu durumda dual‑support (her iki yöntemi aynı anda sunma) stratejisi benimsemek gerekir; bu da CI/CD pipeline’da ekstra test senaryosu eklemek anlamına gelir.
Uygulama Rehberi – Hangi Yöntemi Nasıl Uygulamalıyım?
1. Versiyon Stratejinizi Belirleyin
- Kısa vadeli değişiklikler için header‑based tercih edin. Ben bir feature flag ile
v2’yi devreye alırken,Accept: application/vnd.myapi.v2+jsonekledim ve yalnızca küçük bir kullanıcı dilimini etkiledim. - Uzun vadeli, stabil endpoint için URI‑based daha güvenli. Örneğin, dış satıcıların entegrasyonunda URI‑based versioning, dokümantasyon ve güvenlik açısından daha az sürpriz doğuruyor.
2. API Gateway Konfigürasyonu
# Kong plugin örneği (header‑based)
plugins:
- name: request-transformer
config:
add:
headers:
- "X-API-Version: {{request.headers.Accept | regex_replace('.*v([0-9]+).*', '\\1')}}"
# Nginx map (uri‑based)
map $uri $backend {
~^/v1/ backend_v1;
~^/v2/ backend_v2;
}
Yukarıdaki iki snippet, aynı servis içinde iki versiyonlamayı paralel yürütmek için örnek bir yapı sunar.
3. Test ve Monitoring
- Postman koleksiyonunda
Acceptheader’ını varyasyonlu olarak test edin. Ben farklı header kombinasyonları ile hem 200 OK hem de 400 Bad Request cevaplarını test ettim. - Prometheus metriği:
api_version_requests_total{version="v2"}ile versiyon kullanım oranını izleyin. Bu metriği Grafana’da görselleştirirken, belirgin bir kullanım düşüşü için alarm kurdum.
4. Cache Yönetimi
Header‑based kullanıyorsanız, Vary header’ını ekleyin:
Vary: Accept
Bu, CDN’lerin header‑varyantları ayırmasını sağlar. Ben Cloudflare’da Cache-Control: public, max-age=60, stale-while-revalidate=30 gibi bir politika ekleyerek, yeni versiyonların makul bir süre içinde önbelleğe alınmasını sağladım.
Sonuç – Hangisi Daha Pratik?
Deneyimlerime dayanarak, pratiklik açısından iki yaklaşımın da mevcudiyetinin faydalı olduğunu söyleyebilirim. Eğer müşteri entegrasyonları çoğunlukla dış sistemler ve uzun vadeli stabilite talep ediyorsa, URI‑based versioning daha az bakım riski taşıyor. Ancak iç organizasyon içinde hızlı feature rollout ve blue‑green deployment senaryolarında header‑based versioning zaman kazanıyor.
Net pozisyonum: Çoğu durumda header‑based versioning ile başlayıp, kritik dış entegrasyonlar için URI‑based fallback eklemek, hem esnekliği korur hem de sürüm yönetim karmaşasını sınırlar. Bu hibrit model, üretim ortamlarında gözlemlediğim en düşük hata oranı ve en hızlı geçiş süresiyle uyumlu.
Bir sonraki adım olarak, CI/CD pipeline’ınıza versiyon kontrol testlerini ekleyin ve monitoring üzerinden gerçek zamanlı versiyon kullanımını izleyin. Böylece hangi yöntemin sizin ortamınızda daha pratik olduğunu veriyle kanıtlayabilirsiniz.
Daha önceki API gateway konfigürasyonu yazısında, farklı header‑transformasyonlarını nasıl yönettiğimi detaylıca inceleyebilirsiniz.