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

API Versioning Stratejileri: Uygulama Geliştirmede Basitlik mi,…

API versioning stratejileri arasında seçim yaparken karşılaşılan basitlik ve esneklik dengesini kendi deneyimlerimle inceliyorum. Hangi yaklaşım, hangi…

100%

Bir üretim ERP’sinde çalışırken ya da kendi yan ürünlerimin backend’ini geliştirirken en sık karşılaştığım mimari kararlardan biri API versioning stratejisi seçimiydi. Bu kararın basit bir teknik detaydan öte, aslında projenin gelecekteki esnekliğini, bakım maliyetini ve geliştirici deneyimini doğrudan etkilediğini tecrübe ettim. Temelde hep bir ikilem vardı: Hızlıca ayağa kalkmak için basit bir yol mu, yoksa uzun vadede değişime dirençli, esnek bir yapı mı kurmalıydım?

Bu yazıda, yıllar içinde farklı projelerde denediğim API versioning yaklaşımlarını, bunların artılarını ve eksilerini kendi gözümden anlatacağım. Her bir stratejinin hangi durumlarda işe yaradığını, nerede başımın ağrıdığını somut örneklerle paylaşarak, sizin de bu kararı verirken daha bilinçli olmanıza yardımcı olmayı hedefliyorum. Çünkü biliyorum ki kağıt üzerindeki çözümlerle sahadaki gerçekler çoğu zaman birbirini tutmuyor.

Neden API Versioning’e İhtiyaç Duyarız?

API’ler, uygulamaların birbirleriyle konuşmasını sağlayan temel araçlar. Ama zamanla iş gereksinimleri değişiyor, yeni özellikler ekleniyor, veri modelleri evriliyor. Bu değişimler bazen mevcut API’lerin davranışını veya yapısını bozabiliyor. İşte tam da bu noktada versioning devreye giriyor.

Eğer bir API’de breaking change yaparsam, yani mevcut bir endpoint’in çıktısını, girdisini veya davranışını geri uyumlu olmayacak şekilde değiştirirsem, o API’yi kullanan tüm client uygulamaları (mobil, web, diğer servisler) anında bozulur. Bir veri modelindeki ufak bir değişikliğin raporların yanlış üretilmesine yol açması ya da mobil uygulamanın eski versiyonlarının backend’deki bir schema değişikliği yüzünden kilitlenmesi tipik senaryolardır. Versioning, bu tür felaketleri önlemek ve farklı client’ların kendi hızlarında güncellenmesine olanak tanımak için kritik bir mekanizma.

URI Path Versioning: En Yaygın Yaklaşım

URI (Uniform Resource Identifier) path üzerinden versioning, sanırım sektörde en çok gördüğüm ve en basit olan yaklaşımdır. Burada API versiyonu doğrudan URL’in bir parçası olarak belirtilir, örneğin /api/v1/users veya /api/v2/products.

Bu yaklaşımın en büyük artısı, anlaşılırlığı ve keşfedilebilirliğidir. Bir geliştirici, URL’e bakarak hangi versiyonla çalıştığını hemen anlar. Ayrıca, HTTP cache mekanizmalarıyla da gayet uyumludur, çünkü her versiyonun kendi benzersiz URL’i vardır. Birçok projede ilk tercihim bu olmuştur, özellikle hızlıca MVP çıkarmam gereken durumlarda. Nginx üzerinde basit bir location bloğu ile kolayca yönlendirme yapabiliyordum. Ancak, uzun vadede birden fazla versiyonu desteklemeye başladığımda, router konfigürasyonlarının ve kod tabanının biraz karmaşıklaştığını fark ettim. Her versiyon için ayrı kod blokları veya ayrı route dosyaları yönetmek gerekebiliyordu.

# Nginx ile URI Path Versioning örneği
server {
    listen 80;
    server_name api.example.com;

    location /api/v1/ {
        proxy_pass http://backend_v1_service;
        # Diğer proxy ayarları
    }

    location /api/v2/ {
        proxy_pass http://backend_v2_service;
        # Diğer proxy ayarları
    }
}

Yukarıdaki Nginx örneği, /api/v1 ile gelen istekleri backend_v1_service’e, /api/v2 ile gelenleri ise backend_v2_service’e yönlendirir. Bu yapı, özellikle farklı versiyonların farklı microservice’ler tarafından sunulduğu durumlarda oldukça kullanışlıdır. Ancak, eğer aynı microservice içinde birden fazla versiyonu yönetiyorsanız, kodunuz içinde if version == 'v1' gibi kontrol blokları görmeye başlayabilirsiniz ki bu da teknik borcu artırır. Birden fazla eski versiyonun (v1, v2, v3) aynı anda aktif kaldığı durumlarda kodun okunabilirliği hızla düşer; bu, URI versioning’in en sık görülen bedelidir.

Header Versioning: Esnekliğin Bedeli

Header versioning, API versiyonunu HTTP başlıkları (headers) aracılığıyla iletmektir. En yaygın iki yolu vardır: özel bir başlık kullanmak (X-API-Version: 1) veya Accept başlığını kullanıp özel bir media type belirtmek (Accept: application/vnd.myapi.v2+json).

Bu yaklaşımın en cazip yanı, URI’lerin temiz kalmasıdır. Kaynakların URL’i değişmez, sadece istediğiniz temsili başlıklar aracılığıyla istersiniz. Bu durum, özellikle RESTful mimarinin “kaynak odaklılık” prensibine daha uygun hissedilir. Farklı istemcilerin aynı kaynaklara farklı temsillerle erişmesi gerektiğinde bu yöntem esneklik açısından çok iş görür: aynı /users endpoint’inden, X-API-Version: 1 ile eski ve X-API-Version: 2 ile yeni formatta kullanıcı listesi alınabilir. Ancak, bu esnekliğin bir bedeli vardır.

Test etmesi ve hata ayıklaması URI versioning’e göre daha karmaşıktır. Ayrıca, bazı proxy sunucuları veya CDN’ler, Accept veya özel HTTP başlıklarını doğru şekilde işlemeyebilir, bu da önbellekleme veya yönlendirme sorunlarına yol açabilir. Kendi bir yan ürünümün backend’inde bunu denediğimde, basit bir curl komutuyla bile farklı versiyonları denemek URI kadar pratik gelmemişti. Geliştirici ekibinin bu yaklaşıma alışması ve doğru Accept başlığını sürekli hatırlaması zaman almıştı.

# Header Versioning (Custom Header) örneği
curl -H "X-API-Version: 2" https://api.example.com/products/123

# Header Versioning (Media Type) örneği
curl -H "Accept: application/vnd.myapi.v2+json" https://api.example.com/users

Query Parameter Versioning: Hızlı ve Kirli mi?

Query parameter versioning, API versiyonunu URL’in sorgu parametresi olarak iletmektir: /api/resource?version=1 veya /api/resource?v=2.

Bu yöntem, implementasyonu en hızlı olanlardan biridir. Özellikle bir prototip geliştirirken veya iç API’lerde, hızlıca bir versiyonu devreye almam gerektiğinde kullandığım oldu. Geçici bir raporlama API’sinin farklı çıktılarını test etmek için ?format=v1 ve ?format=v2 gibi parametreler kullanmak hızlı denemeler için pratiktir. Tarayıcıdan doğrudan URL’i değiştirerek farklı versiyonları görmek kolaydır, bu da hızlı test senaryoları için avantajlıdır.

Ancak, bu yaklaşımın ciddi dezavantajları var. Öncelikle, HTTP caching mekanizmaları için sorun teşkil edebilir. Farklı sorgu parametreleri, aynı kaynağın farklı versiyonları olsa bile ayrı ayrı önbellek girdileri oluşturabilir, bu da önbellek verimliliğini düşürür. İkincisi, URI’nin semantik anlamını bozar. Bir kaynağın versiyonu, kaynağın kendisinin bir özelliği olmaktan çok, o kaynağın nasıl bir temsilinin istendiğiyle ilgili olmalıdır. ?version=X kullanmak, sanki kaynağın kendisi versionlanmış gibi bir algı yaratır.

# FastAPI ile Query Parameter Versioning örneği
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/")
async def read_items(version: int = Query(1, description="API version")):
    if version == 1:
        return {"message": "Hello from V1"}
    elif version == 2:
        return {"message": "Greetings from V2!"}
    return {"message": "Invalid version"}

Content Negotiation (Media Type Versioning): RESTful Yaklaşım

Content Negotiation, HTTP Accept başlığını kullanarak farklı veri formatlarını veya versiyonlarını talep etme prensibine dayanır. Bu, genellikle application/vnd.company.app.v1+json gibi özel bir media type belirtilerek yapılır. Bu yaklaşım, RESTful mimarinin temel prensiplerinden biri olan “aynı kaynağın farklı temsilleri” fikrine en uygun olanıdır.

Bu yöntemin en büyük avantajı, URI’nin tamamen sabit kalmasıdır. /users kaynağı her zaman /users olarak kalır, ancak client’ın Accept başlığında belirttiği media type’a göre farklı bir temsil (farklı bir veri şeması veya versiyon) döner. Bu durum, özellikle bir kaynağın yaşam döngüsü boyunca farklı ihtiyaçlara göre evrildiği durumlarda çok esneklik sağlar. Bir müşteri projesinde, aynı sipariş kaynağının hem detaylı bir muhasebe görünümüne hem de basit bir mobil uygulama görünümüne sahip olması gerektiğinde bu yaklaşımı değerlendirmiştik. Aynı /orders/{id} endpoint’inden, Accept: application/vnd.company.erp.v1+json ile ERP’ye özel detaylar, Accept: application/vnd.company.mobile.v1+json ile mobil uygulamaya özel özet veriler dönebiliyordu.

# Flask ile Content Negotiation örneği
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/products/<int:product_id>', methods=['GET'])
def get_product(product_id):
    accept_header = request.headers.get('Accept', '')

    if 'application/vnd.myapi.v2+json' in accept_header:
        return jsonify({"id": product_id, "name": f"Product v2 {product_id}", "price_usd": 12.99})
    elif 'application/vnd.myapi.v1+json' in accept_header:
        return jsonify({"id": product_id, "product_name": f"Product v1 {product_id}", "current_price": "12.99 USD"})
    else:
        # Varsayılan veya hataya düşen durum
        return jsonify({"id": product_id, "name": f"Product default {product_id}"})

if __name__ == '__main__':
    app.run(debug=True)

Ancak, bu yaklaşımın da kendine göre zorlukları var. Implementasyonu diğerlerine göre daha karmaşık olabilir ve client’ların doğru media type’ları bilmesi ve kullanması gerekir. Geliştirici araçları ve kütüphaneleri arasında Accept başlığını doğru yönetme konusunda farklılıklar olabilir. Çoğu ekipte bu kadar esnek bir yapıya ihtiyaç olsa bile, karmaşıklığı yönetme maliyeti yüksek olacağı için daha basit bir URI versioning makul bir tercih olabilir. Her zaman basitlik ve esneklik arasında bir trade-off vardır.

Versioning Olmadan İleriye Yönelik Stratejiler: NoVersioning

“Versioning yapmayalım” fikri ilk duyulduğunda kulağa çılgınca gelebilir, ama bazı senaryolarda gayet mantıklı olabilir. Bu yaklaşım, API’yi her zaman geri uyumlu (backward-compatible) tutmaya çalışmak veya breaking change olduğunda tamamen yeni bir endpoint açmaktır.

Buradaki temel felsefe, API’nin evrimini breaking change’leri minimumda tutarak yönetmektir. Örneğin, mevcut bir JSON objesine yeni bir alan eklemek genellikle geri uyumludur, çünkü eski client’lar bu yeni alanı görmezden gelebilir. Ancak, mevcut bir alanı kaldırmak, adını değiştirmek veya veri tipini değiştirmek breaking change’dir. NoVersioning stratejisi izlerken, bu tür breaking change’lerden kesinlikle kaçınmak veya çok dikkatli olmak gerekir. Benzer bir durumu kendi finansal hesaplayıcılarımın backend’inde uygulamıştım. Kullanıcı sayım az olduğu ve API’yi sadece kendi uygulamalarım kullandığı için, breaking change olduğunda tüm client’ları aynı anda güncelleyebiliyordum.

Bu yaklaşımın avantajı, API’nin her zaman en güncel ve tek bir versiyonunun olmasıdır. Client’lar her zaman en son özelliklere erişebilir ve eski versiyonları destekleme yükü ortadan kalkar. Ancak, en büyük dezavantajı, breaking change yönetimidir. Eğer gerçekten breaking change yapmanız gerekiyorsa, eski bir endpoint’i tamamen sonlandırmanız veya yeni bir isimle tamamen yeni bir endpoint açmanız gerekir. Bu da URI versioning’e benzer bir durum yaratır.

-- Geri uyumlu veritabanı şema değişikliği örneği
-- Mevcut 'users' tablosuna yeni bir sütun ekleme
ALTER TABLE users
ADD COLUMN created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP;

-- Mevcut 'products' tablosunda sütun adını değiştirmek breaking change olurdu
-- ALTER TABLE products RENAME COLUMN price TO unit_price; -- Bu kaçınılmalı!

Bu strateji, özellikle iç API’ler, küçük ekipler veya hızlı değişen ürünler için uygun olabilir. Ancak, geniş bir client tabanına sahip, farklı sürümlerin eş zamanlı olarak çalışması gereken halka açık API’ler için genellikle risklidir. İç servisler arası iletişimde, tüm servisler aynı çatı altında ve eş zamanlı deploy ediliyorsa bu mantık iyi çalışır.

Hangi Stratejiyi Ne Zaman Seçmeli? Trade-off Analizi

API versioning stratejisi seçimi, projenin doğasına, client tabanına, geliştirme hızına ve sürdürülebilirlik hedeflerine göre değişir. “Tek doğru yol” diye bir şey yoktur; önemli olan, karşılaştığınız sorunlara en uygun dengeyi bulmaktır. Saha tecrübemde, her projenin kendi dinamiklerinin farklı bir kararı gerektirdiğini gördüm.

Bir üretim ERP’sinde, dışarıdan entegrasyonlar çok olduğu için URI path versioning’i tercih etmiştim. Basit ve anlaşılır olduğu için entegrasyon yapan diğer firmaların adaptasyonu kolay olmuştu. Mobil uygulamalarımın backend’inde ise, daha çok X-API-Version gibi header versioning’i kullandım, çünkü mobil client’ların güncelleme döngüleri web’e göre daha yavaş olabiliyor ve farklı versiyonları uzun süre desteklemem gerekiyordu. Kendi basit yan ürünlerimde ise, bazen query parameter versioning ile hızlıca prototip çıkarıp, stabil hale geldiğinde URI versioning’e geçiş yaptım.

Aşağıdaki tablo, farklı stratejilerin temel özelliklerini ve benim deneyimlerimdeki kullanım senaryolarını özetliyor:

Strateji Avantajlar Dezavantajlar Ne Zaman Kullanırım
URI Path Versioning Basit, keşfedilebilir, cache uyumlu. URI kirliliği, router karmaşası artabilir. Çoğu dışa açık API, çok client’lı sistemler, microservice tabanlı projeler.
Header Versioning URI temiz kalır, esnek, RESTful. Keşfedilebilirlik zor, test karmaşık, proxy sorunları. Karmaşık iç API’ler, aynı kaynağın farklı temsillerine ihtiyaç duyulan durumlarda.
Query Parameter Versioning Hızlı implementasyon, tarayıcıda kolay test. Cache sorunları, semantik bozukluk, güvenlik riski. Hızlı prototipler, iç API’ler, çok basit ve az client’lı uygulamalar.
Content Negotiation RESTful, URI temiz, yüksek esneklik. Implementasyon karmaşık, tooling desteği değişir. Çok katmanlı, büyük kurumsal sistemler, farklı client’ların çok farklı ihtiyaçları varsa.
NoVersioning En basit, her zaman güncel API, bakım yükü az. Breaking change yönetimi zor, sürekli geri uyumluluk. İç API’ler, küçük ekipler, hızlı değişen ürünler, client’ların kontrolümde olduğu yerler.

Bu tabloya bakarken, her bir stratejinin kendine özgü bir “fiyat etiketi” olduğunu unutmamak gerekir. Basitlik genellikle esneklikten ödün verirken, esneklik de beraberinde bir karmaşıklık ve geliştirme maliyeti getirir. Örneğin Content Negotiation gibi esnek bir yaklaşım başta geniş bir hareket alanı sağlasa da, ekip içindeki onboarding ve yeni geliştiricilerin adaptasyonu uzayabilir; bu da projenin toplam maliyetine yansır.

Sonuç: Karar Sürekli Bir Optimizasyon Meselesi

API versioning stratejisi seçimi, tek seferlik bir karar değildir. Projenin yaşam döngüsü boyunca evrilebilir ve ihtiyaçlar değiştikçe farklı yaklaşımlara geçiş yapmak gerekebilir. Önemli olan, seçtiğiniz stratejinin projenizin mevcut ihtiyaçlarına ve gelecekteki büyüme planlarına uygun olmasıdır. Kendi kariyerimde gördüğüm en büyük hatalardan biri, ilk kararın katı bir şekilde sürdürülmeye çalışılmasıydı, oysa esneklik ve pragmatizm çoğu zaman daha iyi sonuçlar veriyor.

Benim tavsiyem, her zaman en basit çözümle başlamak ve ancak gerçekten ihtiyaç duyulduğunda daha karmaşık stratejilere geçiş yapmaktır. Bu, gereksiz mühendislik yapmaktan kaçınmanızı ve “olur o kadar” felsefesiyle ilerlemenizi sağlar. Unutmayın, API’ler yaşayan organizmalar gibidir; zamanla büyür, değişir ve evrilirler. Önemli olan, bu evrimi kontrollü ve sürdürülebilir bir şekilde yönetmektir.

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.

API versioning stratejisini seçerken nelere dikkat etmem gerekiyor?
Benim deneyimime göre, API versioning stratejisini seçerken, projenin gelecekteki esnekliğini, bakım maliyetini ve geliştirici deneyimini etkileyen faktörlere dikkat etmeniz gerekiyor. Örneğin, hızlıca ayağa kalkmak için basit bir yol mu, yoksa uzun vadede değişime dirençli, esnek bir yapı mı kurmalısınız? Bu kararı verirken, projenin ölçeği, kompleksitesi ve değişim hızı gibi faktörleri dikkate almanız önemlidir.
API versioning stratejilerini uygulamaya başlarken nelere dikkat etmem gerekiyor?
Benim deneyimime göre, API versioning stratejilerini uygulamaya başlarken, mevcut API'lerin davranışını veya yapısını bozabilecek değişikliklere dikkat etmeniz gerekiyor. Örneğin, breaking change yapmadan önce, tüm client uygulamalarının etkilenip etkilenmeyeceğini değerlendirmelisiniz. Ayrıca, versioning stratejisinin dokümantasyonuna ve testlerine dikkat etmeniz önemlidir.
Hangi API versioning stratejisi daha avantajlıdır: URI-based mi, header-based mi?
Benim deneyimime göre, her iki stratejinin de avantajları ve dezavantajları vardır. URI-based yaklaşım daha basit ve anlaşılırken, header-based yaklaşım daha esnek ve ölçeklenebilir olabilir. Örneğin, URI-based yaklaşım, client uygulamalarının farklı versiyonlara kolayca geçiş yapmasını sağlar, ancak bu yaklaşım daha fazla endpoint oluşturabilir. Header-based yaklaşım ise, daha az endpoint oluşturur, ancak client uygulamalarının header'ları doğru şekilde ayarlamasını gerektirir.
API versioning stratejisi seçerken hatalar doingiliz ne yapmalıyız?
Benim deneyimime göre, API versioning stratejisi seçerken, hatalar doingiliz ne yapacağınızı planlamanız önemlidir. Örneğin, breaking change yaptığınızda, client uygulamalarının nasıl etkilenacağını değerlendirerek, gerekli önlemleri alabilirsiniz. Ayrıca, versioning stratejisinin testlerine ve dokümantasyonuna dikkat ederek, hataların erken tespit edilmesini sağlayabilirsiniz. Ben, hatalar doingiliz ne yapacağımı planlarken, всегда bir geri dönüş planı oluşturmayı ve client uygulamalarının etkilenmesini minimize etmeyi hedefliyorum.
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