İçeriğe Atla
Mustafa Erbay
Rehberler · 11 dk okuma · görüntülenme Read in English

API Versioning: URI vs Header – Hangisi Daha Pratik?

API Versioning konusunda URI ve Header yaklaşımlarını gerçek dünyadan örneklerle karşılaştırıyor, trade‑offleri ve pratik uygulamaları anlatıyorum.

100%

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.log satı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 (/orders tek bir yer).
  • Versiyon geçişi daha esnek: Client’lar aynı URL’i tutarak Accept header’ı 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 Accept gibi içerik header’ları proxy katmanında düşebiliyor. Çözüm: fallback olarak X-API-Version header’ı 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+json ekledim 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 Accept header’ı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.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

URI‑tabanlı versiyonlamayı mevcut bir projeye nasıl ekleyebilirim ve hangi araçları kullanmalıyım?
Ben önce API gateway ya da ters proxy katmanını (NGINX, Traefik vb.) açtım ve her versiyon için ayrı bir upstream tanımladım. NGINX’de `map $uri $backend { ~^/v1/ backend_v1; ~^/v2/ backend_v2; }` gibi bir kural ekleyerek URL‑yi doğrudan backend’e yönlendirdim. Sonra uygulama kodunda controller ya da route sınıflarını `@Path("/v1/orders")` ve `@Path("/v2/orders")` gibi iki ayrı paket içinde oluşturdum. Swagger/OpenAPI dosyalarını iki ayrı dosya halinde tutup, CI‑pipeline’da her versiyon için ayrı bir artefakt üretmek, dokümantasyonu ve testleri izole eder. Bu adımları otomatikleştirmek için GitHub Actions ya da GitLab CI kullanıyorum; böylece yeni bir versiyon eklediğimde sadece map ve routing dosyası güncellenir, diğer servisler etkilenmez.
Header tabanlı versiyonlama kullanırken karşılaştığım en büyük dezavantaj nedir ve bu sorunu nasıl hafifletebilirim?
Benim en büyük sorunum, CDN ve proxy cache’lerinin `Accept-Version` gibi özel header’ları varsayılan olarak görmezden gelmesiydi; bu da eski yanıtların önbellekte kalmasına ve yeni sürümün istemciye ulaşmamasına yol açtı. Çözüm olarak, her yanıtın `Cache‑Control: no‑cache, must‑revalidate` ekledim ve CDN konfigürasyonunda header‑varyasyonu (`Vary: Accept-Version`) tanımladım. Ayrıca, Spring Boot’da bir `HandlerInterceptor` yazarak header‑ı kontrol edip, eksikse 400 hatası döndürdüm; bu sayede hatalı istekler erken yakalandı. Dokümantasyonda header‑ı zorunlu kıldığım ve örnek curl komutları verdiğim için ekip içinde tutarlılık sağlandı.
Versiyonlama hatası alırsam log ve monitoring'de neye bakmam gerekir, hatayı nasıl hızlıca izole edebilirim?
Ben önce NGINX access.log’da `/v2/` gibi bir pattern ararım; isteklerin hangi backend’e yönlendirildiğini ve HTTP status kodunu görürüm. Ardından uygulama logunda (`application.log`) versiyon header’ı (`Accept-Version`) ya da URL segmentini içeren bir MDC (Mapped Diagnostic Context) ekleyerek, hatalı istekleri filtreleyebiliyorum. Grafana‑Prometheus dashboard’unda “api_version_requests_total” ve “api_version_errors_total” gibi custom metric’ler tanımladım; bu sayede anormallik anında alarm geliyor. Jaeger ya da Zipkin ile distributed tracing’i aktif tutarak, hatanın hangi mikroserviste (örnek: backend_v2) oluştuğunu ve stack trace’i hızlıca bulabiliyorum. Böyle bir izleme zinciri, sorunu hızla izole edip geri dönüş planını devreye sokmamı sağladı.
Toplulukta "Header‑tabanlı versiyonlama daha modern ve tercih ediliyor" miti var. Bu doğru mu?
Ben bu miti deneyimle çürüttüm; header‑tabanlı versiyonlama gerçekten temiz bir URL tutsa da, gerçek dünyada cache, CDN ve API gateway’lerin çoğu URL‑yönlendirmeyi tercih eder. Ben bir e‑ticaret projesinde header‑versiyonlamayı denediğimde, CDN‑in vary‑header’ı desteklemediği için eski içerik önbellekte kalıyordu ve müşteriler yeni alanları göremiyordu. URI‑versiyonlama ise cache‑friendly olduğu için CDN‑ler otomatik olarak yeni sürüme geçişi yapar. Dolayısıyla "daha modern" demek teknik olarak doğru olsa da, operasyonel bakım ve performans açısından URI‑tabanlı yaklaşım hâlâ daha pratik ve güvenilir bir seçim.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar