Mobil ekiplerde API versiyonlama, web ekiplerinden çok daha ağır bir sorumluluk taşır: bir web sayfası her istekte yeniden yüklenir ama bir mobil uygulama App Store'da onaylanana kadar günlerce eski API sözleşmesiyle çalışmaya devam eder. Bu yazıda API versiyonlama geriye dönük uyumluluk konusunu URL/header/media-type yaklaşımlarından deprecation takvimine kadar somut örneklerle ele alıyoruz; amaç, sunucu tarafında breaking change yapmadan büyüyebilen bir sözleşme kurmak.
💡 Pro Tip: Yeni bir alan eklemek asla breaking change değildir; bir alanı kaldırmak veya anlamını değiştirmek her zaman öyledir. Bu tek cümleyi ekip kuralına dönüştürürsen versiyonlama tartışmalarının çoğu kendiliğinden çözülür.
İçindekiler
- Mobilde Versiyonlama Neden Webden Zor
- Üç Yaklaşım: URL Path, Header, Media Type
- URL Path Versiyonlama (`/v1/users`)
- Header Tabanlı Versiyonlama
- Media Type (Content Negotiation) Versiyonlama
- Breaking Change'in Gerçek Tanımı (İstemci Gözünden)
- Additive-Only Tasarım: Alan Ekle, Asla Kaldırma
- Deprecation Takvimi ve Sunset/Deprecation Header'ları
- Zorunlu Güncelleme Kapısı ve Minimum Desteklenen Sürüm
- Eski Sürüm Trafiğini Ölçmek (Kararı Veriye Bağlamak)
- Migration'ı İstemciye Taşımadan Sunucuda Absorbe Etmek
- Yaklaşımların Karşılaştırması
- Değişiklik Türü ve Versiyon Etkisi
- SSS
- API versiyonlaması URL'de mi header'da mı olmalı?
- Eski uygulama sürümlerini ne kadar süre desteklemeliyim?
- Deprecation politikası nasıl yazılır?
- Zorunlu güncelleme (force update) ekranı nasıl tasarlanır?
- Güncelleme (Eylül 2026)
- Sonuç
- Kaynaklar
Mobilde Versiyonlama Neden Webden Zor
Bir web istemcisi API sözleşmesini genelde saatler içinde günceller: kullanıcı sayfayı yeniler, yeni JavaScript bundle'ı gelir. Mobil istemcide bu döngü yok. Bir binary App Store/Play Store incelemesinden geçer, kullanıcı güncellemeyi hemen yapmayabilir ve cihazda internet olmadan güncelleme de gerçekleşmez. Sonuç: sunucu, aynı anda haftalar hatta aylar boyunca birden fazla istemci sözleşmesini desteklemek zorunda kalır. Bu yüzden mobil backend'de versiyonlama kararı, bir web API'sinde olduğundan çok daha uzun bir "geriye uyumluluk penceresi" gerektirir ve sözleşme değişiklikleri, dağıtım hızından değil mağaza inceleme süresinden ve kullanıcı güncelleme alışkanlığından etkilenir.
Bu farkın pratik sonucu, sunucu tarafındaki tek bir endpoint'in aynı anda üç-dört farklı sözleşme şeklini doğru şekilde yanıtlayabilmesi gerektiğidir: en yeni istemci sürümü, bir önceki büyük sürüm ve hâlâ trafik üreten daha eski sürümler. Web tarafında bu senaryo neredeyse hiç oluşmaz çünkü tarayıcı her ziyarette güncel kodu çeker; mobilde ise bu, sunucu kodunun normal, günlük bir gereksinimidir — versiyonlama "bazen gereken" bir özellik değil, sürekli işletilen bir sözleşme yönetimi disiplinidir.
Üç Yaklaşım: URL Path, Header, Media Type
API versiyonlamada üç yaygın teknik var ve bunların hiçbiri "evrensel doğru" değil; her biri farklı bir varsayımı optimize eder.
URL Path Versiyonlama (`/v1/users`)
En yaygın ve en tartışmalı yöntem. Okunması kolay, cache'lemesi kolay, ama Zalando RESTful API Guidelines açıkça bunu önermez: kural "MUST not use URL versioning" olarak yazılmış — gerekçe, URL versiyonlamanın istemci-sunucu arasında daha sıkı bir bağlılık yaratması ve hyperlink'li servis bağımlılıklarında versiyon yükseltmesini koordine etmeyi zorlaştırmasıdır (tüketici, sağlayıcı yükseltmeyi bitirene kadar beklemek zorunda kalır); bunun yerine media type versiyonlama + content negotiation zorunlu tutulur. Ayrı bir genel REST argümanı olarak da şu söylenebilir: kaynağın kimliği URL'de sabit kalmalı, versiyon ise bir temsil detayıdır.
Mobil tarafta bu teorik itirazın somut bir karşılığı var: bir kullanıcı kaydını /v1/users/42 ve /v2/users/42 iki ayrı URL olarak modellersen, istemci tarafında deep link'ler, push bildirim payload'ları ve offline cache anahtarları da versiyon bilgisini taşımak zorunda kalır. Uygulama içi bir bildirim linki /v1/users/42 kaydedip kullanıcı iki ay sonra tıkladığında, o sırada sunucu yalnızca /v2/ sunuyorsa link kırılır — oysa aynı kaynağı sabit bir URL'de tutup versiyonu header'a taşısan bu sorun hiç oluşmaz.
Header Tabanlı Versiyonlama
Microsoft'un Azure API Guidelines'ı query-parametre (api-version) ile versiyon taşınmasını ve deprecation bildirimleri için azure-deprecating header'ını tanımlar; bu iki mekanizma birlikte, istemcinin her istekte hangi sözleşmeyi beklediğini hem query string'de hem de yanıt başlığında görünür kılar. Stripe'ın 2017 tarihli mühendislik blog yazısı ise aynı problemi farklı bir açıdan çözer: bir hesap ilk API isteğini yaptığı anda o günün en yeni versiyonuna otomatik pinlenir ve versiyonlar tarihle adlandırılır — kendi ifadeleriyle sürümler «named with the date they're released (for example, 2017-05-24)»; hesap açıkça yükseltmediği sürece o versiyonda kalır ve her istek Stripe-Version header'ı ile hangi sözleşmeyi beklediğini belirtir. Azure'ın query-parametresi ile Stripe'ın header'ı, aynı temel fikri iki farklı taşıyıcıyla hayata geçirir: versiyon bilgisini URL'nin kaynak kısmından ayırıp isteğin kendisine taşımak. Pratik farkları da var: Azure'ın api-version query-parametresi istemci tarafında eklemesi en kolay olanıdır (URL'ye tek bir sorgu parametresi eklemek yeter) ama query string'ler proxy/CDN loglarına düz metin olarak düşebilir; Stripe'ın Stripe-Version header'ı ise isteğin gövdesinden ayrı bir kanal olduğu için loglanma alışkanlıkları farklıdır ve sunucu tarafında hesap bazlı bir varsayılana (pinlenmiş versiyona) düşebilir — istemci header'ı hiç göndermese bile hesabın son pinlendiği versiyon geçerli olur. Mobil bir istemci için bu ikinci davranış özellikle değerlidir: bir uygulama güncellemesi App Store incelemesinde beklerken sunucu tarafı yine de o hesabın beklediği sözleşmeyi bilir, çünkü versiyon bilgisi istemcinin her seferinde doğru header'ı göndermesine değil, sunucudaki kayda dayanır.
http
1GET /users/42 HTTP/1.12Host: api.example.com3Accept-Version: 2025-05-20Media Type (Content Negotiation) Versiyonlama
Zalando'nun aynı rehberi, URL versiyonlamayı reddederken media-type versiyonlamayı (custom Accept header ile MIME type üzerinden) zorunlu kılıyor. Sunucu, Accept: application/vnd.example.v2+json gibi bir header'a göre farklı temsil döndürür; kaynağın URL'si sabit kalır.
http
1GET /users/42 HTTP/1.12Accept: application/vnd.example.v2+jsonMobil tarafta pratik seçim genelde header/media-type tarafına kayar, çünkü URL sabit kalınca deep link'ler ve cache anahtarları kırılmaz; versiyon bilgisini yalnızca istek başlığı taşır.
Üçüncü bir seçenek de tarih formatlı versiyon değeridir; Stripe'ın modeli bunu zaten kullanır çünkü 2017-05-24 gibi bir değer, ekip için hem sıralanabilir hem de "hangi tarihte donduruldu" sorusuna doğrudan cevap verir. Bu üç yaklaşımı birbirine karşı seçerken tek bir doğru cevap aramak yerine şu soruyu sormak daha isabetlidir: istemcinin URL'yi cache'lemesi mi, yoksa sunucunun kaç farklı sözleşmeyi aynı anda taşıması gerektiğini kolayca görebilmesi mi daha kritik? URL versiyonlama birinciyi, header/tarih tabanlı versiyonlama ikinciyi kolaylaştırır.
Breaking Change'in Gerçek Tanımı (İstemci Gözünden)
semver.org'un tanımına göre bir MAJOR sürüm artışı, "uyumsuz API değişiklikleri yaptığında" yapılır — yani semver'in kendi sözleşmesi breaking change'i doğrudan "geriye uyumsuzluk" ile eşitler. Bir mobil istemci gözünden bu şu üç durumdan biri anlamına gelir: (1) istemcinin beklediği bir alan artık gelmiyor, (2) var olan bir alanın tipi veya anlamı değişti, (3) istemcinin gönderdiği bir isteğin artık kabul edilmemesi (zorunlu yeni parametre, kaldırılmış endpoint). Buna karşılık yeni bir alan eklemek, yeni bir opsiyonel parametre tanımlamak veya yeni bir endpoint açmak — istemci bunu okumasa bile — breaking change SAYILMAZ. Bu ayrımı net tutmak, "her değişiklik yeni versiyon ister mi" tartışmasını bitirir.
Additive-Only Tasarım: Alan Ekle, Asla Kaldırma
Stripe'ın 2017 tarihli mühendislik blog yazısı, API versiyonlama stratejisini şu ilkeye dayandırır: bir hesap ilk API isteğini yaptığında o an mevcut en yeni versiyona otomatik pinlenir ve hesap açıkça yükseltmediği sürece o versiyonda kalır; her istek Stripe-Version header'ı ile hangi sözleşmeyi beklediğini belirtebilir. Bu modelin arkasındaki pratik kural additive-only tasarımdır: yeni bir özellik geldiğinde var olan alanlar korunur, yalnızca yeni alanlar eklenir; bir alanın kaldırılması veya davranışının değiştirilmesi ayrı bir versiyon dönüşü gerektirir.
json
1{2 "id": "usr_42",3 "email": "[email protected]",4 "phone_verified": true5}Yukarıdaki gövdeye "marketing_opt_in": false gibi yeni bir alan eklemek eski istemcileri etkilemez — istemci onu okumaz, sunucu onu göndermeye devam eder. Ama "phone_verified" alanının adını "phoneVerified" yapmak veya tipini "true" (string) olarak değiştirmek, o alanı okuyan her eski istemciyi anında kırar.
Additive-only tasarımın sınırı da net: bir alanı "kullanılmıyor" diye boş bırakmak veya sessizce farklı bir anlamla doldurmak (örneğin bir zamanlar kullanıcı adı taşıyan bir alanın artık kullanıcı ID'si döndürmesi) additive değildir — alan hâlâ orada olsa bile semantiği değiştiği için eski istemci yanlış veriyi doğru sanarak işler. Bu yüzden "alanı silmedim" tek başına yeterli güvence değildir; alanın anlamının da değişmediğini garanti etmek gerekir.
Deprecation Takvimi ve Sunset/Deprecation Header'ları
Bir alanı veya endpoint'i tamamen kaldırmadan önce, istemcilere bunu makine tarafından okunabilir şekilde bildirmenin standart bir yolu var. RFC 8594, 2019'da yayımlanmış bir Informational RFC olarak Sunset HTTP header'ını tanımlar: bir kaynağın hangi tarihte tamamen devre dışı kalacağını belirtir. Bunu tamamlayan Deprecation header'ı ise RFC 9745 ile Mart 2025'te IETF Standards Track (Proposed Standard) olarak yayımlandı — bu header, bir kaynağın _artık_ kullanımdan kaldırılmış olduğunu (henüz kapatılmamış olsa bile) bildirir. İkisi birlikte kullanıldığında istemciye iki ayrı zaman bilgisi verilmiş olur: "bu artık deprecated" (Deprecation) ve "şu tarihte tamamen kapanacak" (Sunset).
http
1HTTP/1.1 200 OK2Deprecation: @17476992003Sunset: Wed, 20 Aug 2025 00:00:00 GMT4Link: <https://api.example.com/docs/migration-v2>; rel="deprecation"Pratik kural: bir alanı veya endpoint'i kaldırmadan önce önce Deprecation header'ıyla işaretle, ardından yeterince uzun bir geçiş penceresinden sonra Sunset tarihini ekle; istemci tarafında bu header'ları loglayan/uyaran bir katman olmadan bu bildirimler sessizce görmezden gelinir.
Header'ların kendisi kadar önemli olan bir nokta da bunları nerede tükettiğindir. Sunucu response'una Deprecation header'ını eklemek tek başına yeterli değildir; mobil istemci tarafında bu header'ı okuyup bir log satırına veya (varsa) geliştirici build'lerinde görünür bir uyarıya çeviren küçük bir ara katman (interceptor) olmadan bu bilgi sessizce kaybolur — üretim build'inde kullanıcıya gösterilmez ama en azından telemetriye düşer, böylece ekip "bu alan hâlâ kaç istekte kullanılıyor" sorusunu header'ın kendisinden, ayrı bir dokümandan değil, doğrudan cevaplayabilir.
Zorunlu Güncelleme Kapısı ve Minimum Desteklenen Sürüm
Bir noktada, deprecation bildirimleri yetmez ve sunucu bazı eski istemcilerin isteklerini tamamen reddetmek zorunda kalır — bu genelde bir güvenlik açığı kapatıldığında ya da sözleşme o kadar değiştiğinde olur ki eski istemci artık anlamlı çalışamaz. Bunun sunucu tarafındaki karşılığı basittir: her istekte istemcinin gönderdiği versiyon/build numarasını kontrol eden bir minimum-versiyon kapısı. Versiyon bu eşiğin altındaysa sunucu isteği normal yanıt yerine "güncelleme gerekli" anlamına gelen özel bir durum koduyla karşılar; istemci tarafı bunu App Store/Play Store'a yönlendiren bir zorunlu güncelleme ekranıyla çözer. Bu kapının kritik tarafı, eşiğin ne zaman yükseltileceğine dair bir kararın veriye — yani gerçek trafiğe — dayanması, keyfi bir tarihe değil.
Bu kapıyı devreye almadan önce ayrı bir soru daha var: hangi durumlarda tamamen reddetmek yerine "uyar ama yine de çalıştır" davranışı yeterli? Güvenlik açığı gibi geri dönüşü olmayan durumlarda sert red mantıklıdır; ama sadece yeni bir özelliği desteklememe gibi durumlarda eski istemciyi tamamen kapatmak yerine o özelliği içermeyen bir yanıt döndürmek (graceful degradation) genelde daha az sürtünme yaratır. Kapının kendisi tek bir anahtar değil, "reddet" ve "eksik ama çalışır yanıt ver" arasında bilinçli seçilmiş bir spektrum olmalı.
Eski Sürüm Trafiğini Ölçmek (Kararı Veriye Bağlamak)
Zorunlu güncelleme eşiğini ne zaman yükselteceğine dair en sık yapılan hata, kararı bir varsayıma ("kimse artık o kadar eski sürümde değildir") dayandırmaktır. Bunun yerine sunucu tarafında her isteğin istemci versiyon/build bilgisini (header'dan veya User-Agent'tan) yapılandırılmış bir log alanına yazmak ve bu alanı versiyon başına gruplayarak izlemek gerekir. Bu, üç ayrı soruya somut cevap verir: hangi versiyonlar hâlâ trafik üretiyor, o trafiğin payı zamanla düşüyor mu yükseliyor mu, ve bir versiyonu tamamen kapatmanın etkileyeceği gerçek kullanıcı sayısı ne. Böyle bir ölçüm katmanı olmadan zorunlu güncelleme veya endpoint kapatma kararı kör bir tahmin olmaktan öteye geçmez.
ts
1// version-metrics.ts — istemci versiyonunu istek başına etiketle2function recordClientVersion(req: Request, metrics: MetricsClient) {3 const version = req.headers.get("x-client-version") ?? "unknown";4 metrics.increment("api.requests_by_client_version", { version });5}Bu tek fonksiyon küçük görünür ama iki farklı kararı besler. Birincisi, "artık kapatabilir miyiz" sorusuna zaman içindeki eğriyle cevap verir — bir versiyonun payı sıfıra yakınsıyorsa kapatma kararı verilerle desteklenir. İkincisi, kapatma kararından SONRA da işe yarar: kapatma sonrası aynı metrik panelinde beklenmedik bir sıçrama (unknown etiketinin artması gibi) olursa bu, bazı istemcilerin header'ı hiç göndermediğini ve kapatmanın öngörülenden daha geniş bir kitleyi etkilediğini erken haber verir.
Migration'ı İstemciye Taşımadan Sunucuda Absorbe Etmek
En düşük sürtünmeli geçiş stratejisi, eski istemciyi hiç güncellemeye zorlamadan sözleşme farkını sunucu tarafında kapatmaktır. Bunun somut yolu, eski versiyon isteğini karşılayan bir adaptör katmanıdır: sunucu içeride yeni (v2) modeli kullanır, ama v1 isteği geldiğinde yanıtı v1 şekline dönüştüren ince bir dönüştürme fonksiyonundan geçirir.
ts
1// adapters/user-v1.ts2function toV1Shape(userV2: UserV2): UserV1 {3 return {4 id: userV2.id,5 email: userV2.email,6 // v2'de ayrılan iki alan, v1 istemcisi için tekrar birleştirilir7 name: `${userV2.firstName} ${userV2.lastName}`,8 };9}Bu yaklaşımın maliyeti sunucuda birkaç adaptör fonksiyonu tutmaktır; kazancı ise istemcinin hiçbir zaman "acilen güncelle" baskısı hissetmemesidir — geçiş tamamen sunucu deploy'una bağlı kalır ve mağaza inceleme süresi migration'ın önünde engel olmaz.
Bu deseni ölçekli tutmanın anahtarı, adaptör fonksiyonlarını iş mantığından ayrı, tek bir dizinde toplamaktır. Aksi halde her yeni v1/v2/v3 dönüşümü ana servis koduna dağılır ve hangi alanın hangi versiyon için dönüştürüldüğünü takip etmek zorlaşır. Pratikte bu, sunucu içinde tek bir "kanonik" model (en yeni sözleşme) ve bu modelden geriye doğru her desteklenen versiyona bir dönüştürücü tutmak anlamına gelir; yeni bir versiyon eklendiğinde tek yapılması gereken yeni bir dönüştürücü yazmaktır, var olanları değiştirmek değil.
Yaklaşımların Karşılaştırması
Üç yöntemi mobil bağlamda yan yana koyarsak:
Yaklaşım | Kaynak URL'i değişir mi | Cache/deep-link etkisi | Kaynak |
|---|---|---|---|
URL path ( /v2/...) | Evet | Yüksek (her versiyon ayrı URL) | Zalando (karşı görüş) |
Header/media-type | Hayır | Düşük | Zalando |
Tarih formatlı versiyon | Bağlama göre | Düşük-orta | Stripe, Azure API Guidelines |
Değişiklik Türü ve Versiyon Etkisi
Değişiklik | Breaking mi | semver etkisi |
|---|---|---|
Yeni opsiyonel alan ekleme | Hayır | Minor |
Var olan alanı kaldırma | Evet | MAJOR |
Alan tipini değiştirme | Evet | MAJOR |
Yeni endpoint açma | Hayır | Minor |
Zorunlu yeni parametre isteme | Evet | MAJOR |
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
Okuyucu Ödülü
Bir API değişikliği yapmadan önce kendine sorman gereken soruların düz bir listesini aşağıda bırakıyorum; her madde "evet" ise değişiklik güvenle additive kabul edilebilir, herhangi biri "hayır" ise MAJOR versiyon ve deprecation takvimi gerekir.
SSS
API versiyonlaması URL'de mi header'da mı olmalı?
İkisi de kullanılıyor ama Zalando RESTful API Guidelines açıkça URL versiyonlamayı önermiyor ("MUST not use URL versioning") çünkü URL versiyonlama istemci-sunucu bağlılığını sıkılaştırıyor ve hyperlink'li servis bağımlılıklarında versiyon koordinasyonunu zorlaştırıyor; bunun yerine media-type/header tabanlı versiyonlamayı zorunlu tutuyor. Mobil backend'lerde header/media-type yaklaşımı, deep link ve cache anahtarlarını sabit tuttuğu için genelde daha az sürtünme yaratır.
Eski uygulama sürümlerini ne kadar süre desteklemeliyim?
Sabit bir sayı vermek yanıltıcı olur çünkü süre projeden projeye değişir. Somut kural şu: süreyi bir varsayıma göre değil, "Eski Sürüm Trafiğini Ölçmek" bölümünde anlatılan versiyon-bazlı trafik ölçümüne göre belirle ve bir versiyonu kapatmadan önce onun gerçek trafik payının anlamlı şekilde düştüğünü doğrula.
Deprecation politikası nasıl yazılır?
RFC 9745'in tanımladığı Deprecation header'ı ile bir kaynağın artık kullanımdan kaldırıldığını, RFC 8594'ün Sunset header'ı ile de hangi tarihte tamamen kapanacağını makine tarafından okunabilir şekilde bildir. Bu iki header'ı dokümantasyondaki insan-okunur bir metinle değil, gerçek HTTP yanıtlarında gönder; böylece istemci tarafında otomatik uyarı/log mekanizmaları kurulabilir.
Zorunlu güncelleme (force update) ekranı nasıl tasarlanır?
Sunucu tarafında istemci versiyonunu kontrol eden bir minimum-versiyon kapısı kur; eşiğin altındaki istekleri normal yanıt yerine özel bir durumla karşıla, istemci de bunu kullanıcıyı mağazaya yönlendiren tam ekran bir güncelleme uyarısıyla çöz. Kapının sunucu tarafındaki mantığı yukarıdaki "Zorunlu Güncelleme Kapısı" bölümünde anlatıldı; ekranın kendisi kapatılabilir olmamalı, kullanıcının mağaza sayfasına gitmesi dışında bir çıkış yolu sunmamalı.
Güncelleme (Eylül 2026)
Bu yazı ilk olarak 2025-05-20 tarihinde, o günün araç ve standartlarıyla yazıldı. O tarihten sonra sahada iki somut gelişme oldu:
- Deprecation header'ı üretimde canlı örneğe kavuştu. GitHub REST API'si Deprecation (RFC 7231 HTTP-date) ve Sunset (RFC 8594) header'larını, kapanmaya yaklaşan bir versiyon için yanıtlarında gönderiyor; politikası, yeni bir versiyon çıktıktan sonra öncekini en az 24 ay daha desteklemek. GitHub'ın güncel versiyonu 2026-03-10, 2022-11-28'in destek bitişi 10 Mart 2028 (docs.github.com/en/rest/about-the-rest-api/api-versions). Bu, makalede anlatılan iki-aşamalı deprecation modelinin (önce Deprecation bildirimi, sonra Sunset tarihi) artık büyük bir platformda canlı örneği olduğu anlamına gelir.
- OpenAPI Specification v3.2.0 (2025-09-19), spesifikasyona "Versions and Deprecation" bölümünü ekleyerek OAS'ın kendi deprecated alan/özelliklerinin yaşam döngüsü politikasını yazılı hale getirdi (spec.openapis.org/oas/v3.2.0.html).
Google AIP-185, publish_date sonrası genişledi. 2025-05-20 itibarıyla AIP-185 yalnız Channel-based / Release-based / Visibility-based stratejilerini listeliyordu ve REST API'ler için major versiyonun URI path'inin ilk parçası olarak taşınmasını şart koşuyordu. Rehber daha sonra Interface-based versioning bölümünü ekleyerek X-Goog-Api-Version HTTP header'ı veya $apiVersion URL query-parametresi ile taşınan, YYYY-MM-DD formatlı (örn. 2025-09-04) tarihli stabil versiyonları da resmi bir strateji hâline getirdi (google.aip.dev/185).
Mobil tarafta ayrıca iki mağaza kuralı, "eski sürüm ne kadar desteklenir" sorusuna dolaylı bir alt sınır getirdi: Google Play, yeni uygulama ve güncellemeler için 2026-08-31 itibarıyla Android 16 (API 36) hedeflemesini zorunlu kıldı (developer.android.com/google/play/requirements/target-sdk); Apple, 28 Nisan 2026'dan itibaren App Store Connect'e yüklenen uygulamaların Xcode 26 ve iOS 26 SDK'sıyla derlenmiş olmasını şart koşuyor (developer.apple.com/news/upcoming-requirements/). Bu tarihler API sözleşmesiyle ilgili değil ama binary'nin kendisiyle ilgili zorunlu güncelleme baskısını artırıyor — yani sunucu tarafındaki minimum-versiyon kapısının eşiğini gözden geçirmek için ek bir tetikleyici oluşturuyor.
Sonuç
API versiyonlama, mobilde tek seferlik bir teknik karar değil, sürekli işletilen bir disiplindir: additive-only tasarım kırılmaları en aza indirir, Deprecation/Sunset header'ları istemciyi makine tarafından okunabilir şekilde uyarır, ve minimum-versiyon kapısı gerçek trafik verisine dayanarak devreye girer. Sözleşme değişikliğini istemciye değil sunucudaki adaptör katmanına taşımak, mağaza inceleme süresinin migration'ın önünde engel olmasını engeller.
Konuyla ilgili derinleşmek için: API sözleşmesinin temel prensiplerine REST API tasarım prensipleri yazısından bakabilirsin; sunucu tarafı performans ve sorgu maliyetleri için database indexing ve query performansı rehberi tamamlayıcı; mobil backend güvenliği açısından API güvenliği: mobil backend yazısı bu makaledeki header tabanlı yaklaşımların güvenlik tarafını kapatıyor. Sunucu tarafında Vapor gibi bir Swift backend kullanıyorsan Swift Vapor ile backend API yazısı somut kurulum adımlarını gösteriyor; versiyonlama kararlarını ekip sürecine bağlamak istersen mobil ekipte teknik borç yönetimi yazısı bu tür kararların nasıl önceliklendirileceğini ele alıyor.
Kaynaklar
- semver.org — Semantic Versioning 2.0.0 spesifikasyonu; MAJOR sürümün "uyumsuz API değişiklikleri" ile tanımı.
- Zalando RESTful API Guidelines — URL versiyonlama karşıtı kural ve media-type versiyonlama zorunluluğu.
- Microsoft Azure API Guidelines — query-parametre (
api-version) versiyonlama veazure-deprecatingheader tanımı. - Stripe Engineering Blog — API Versioning — hesap bazlı versiyon pinleme ve
Stripe-Versionheader modeli (2017). - RFC 8594 — The Sunset HTTP Header Field — Informational RFC, 2019.
- RFC 9745 — The Deprecation HTTP Response Header Field — IETF Proposed Standard, Mart 2025.
- GitHub REST API Versions — Deprecation (RFC 7231 HTTP-date) ve Sunset (RFC 8594) header'larının üretimde kullanımı, versiyon
2026-03-10. - OpenAPI Specification v3.2.0 — 2025-09-19, spesifikasyona "Versions and Deprecation" bölümü eklendi.

