Referans Rehberi · API'ler

İstemci sis­tem­le­rini bozmadan API sürüm­leme

Herkese açık bir API, başkasının koduyla yapılmış bir sözleşmedir. Müşterilerin production ortamını kırmadan nasıl geliştirilir? CTO'lar, API mimarları ve backend ekipleri için.

Bu nedir? · Referans Rehberi

Bir mühendislik sorusunu ayrıntılı olarak ele alan teknik rehber. Önerilerin avantajlarını, maliyetlerini, sınırlamalarını ve hangi koşullarda farklı bir seçimin uygun olacağını açıklar. Genel bakışa git

Yazar
Batunet Engineering
Okuma süresi
11 dk
Seviye
Derinlemesine
Durum
Onaylandı
Son inceleme
21 Temmuz 2026
Güncelleme
21 Temmuz 2026
Bu sayfada

Başka bir sistem API'nizi çağırdığı anda kodunuzun bir kısmı artık yalnızca size ait değildir. Döndürdüğünüz her yanıt, her alan adı, her hata kodu başkasının kodunun güvendiği bir sözdür. Bu yüzden bir API'yi değiştirmek kendi kodunuzu değiştirmek değildir — hiç tanımadığınız insanların production ortamına müdahale etmektir.

API sürümlemenin yazılım mühendisliğinin en affetmez disiplinlerinden biri olmasının nedeni budur. Dahili olarak bir hatayı düzeltebilir, deploy edebilir, yolunuza devam edebilirsiniz. Herkese açık bir arayüzde ise düşünülmeden yapılmış bir değişiklik, harici sistemlerde sessiz bir kesintidir — sizin tarafınızdan değil, müşterinizin müşterisi tarafından fark edilir. Bu metin, bir API'yi bu sözü bozmadan yıllarca nasıl geliştireceğinizi anlatıyor: mümkün olduğunda uyumlu; gerektiğinde düzgün sürümlenmiş; ve kimseyi şaşırtmayan bir çıkışla.


Bir API neden bir sözdür

Bir API'nin sözleşmesi, çağıranın güvenebileceği her şeydir: yanıtın yapısı, alanların anlamı, hataların semantiği, sınır durumlardaki davranış. Bunların çoğu dokümantasyonun hiçbir yerinde yazmaz — belirli bir yanıt biçimi bekleyip ona göre inşa eden müşterilerin kodunda yazar. Gerçek sözleşme, taahhüt ettiğinizden daha büyüktür; müşterilerin gözlemleyebildiği her şeyi kapsar.

Temel tutum buradan çıkar: Herkese açık bir API'de geriye dönük uyumluluk bir nezaket değil, varsayılan ayardır. Yalnızca mevcut çağıranların fark etmeyeceği şekilde değiştirebileceğiniz şeyi değiştirirsiniz — ve görünür her değişikliği olduğu gibi ele alırsınız: harici sistemlere bir müdahale olarak.

Breaking change nedir — ve ne değildir

Sürümleme üzerine düşünmeden önce, neyin gerçekten kırdığını tanımanız gerekir. Sınır “küçük” ile “büyük” arasında değil, “mevcut bir çağıran bunu fark eder” ile “fark etmez” arasından geçer.

Kırıcı olmayanlar genellikle ekleme niteliğindeki değişikliklerdir: yanıtta yeni, opsiyonel bir alan; makul bir varsayılan değere sahip yeni bir opsiyonel parametre; yeni bir endpoint; istemciler bilinmeyen değerleri tolere ediyorsa, genişletilebilir bir enum'da yeni bir değer.

Kırıcı olanlar mevcut bir beklentiyi ihlal eden değişikliklerdir: bir alanı kaldırmak ya da yeniden adlandırmak; bir alanın tipini ya da formatını değiştirmek; şimdiye kadar opsiyonel olan bir alanı zorunlu yapmak; doğrulamayı sıkılaştırmak; bir varsayılan değeri değiştirmek; bir hata kodunun anlamını kaydırmak; birinin güvenebildiği sıralamayı ya da semantiği değiştirmek. Sınırları sıkılaştırmak da — daha düşük bir limit, daha katı bir format — hiçbir alan kaybolmasa bile kırar.

İşin rahatsız edici kısmı: Bazı müşteriler hiç taahhüt etmediğiniz davranışlara güvenir. Bu yüzden en güvenli varsayım, aksi kanıtlanana kadar gözlemlenebilen her değişikliğin birileri için kırıcı olduğudur.

İlke: Yeni sürümden önce uyumlu genişletme

Yeni bir sürüm pahalıdır — sizin için, çünkü iki sözleşme işletirsiniz; müşteriler için, çünkü geçiş yapmak zorundadırlar. Bu yüzden yeni sürüm ilk refleks değil, son çaredir. API baştan evrime göre tasarlandıysa değişikliklerin çoğu uyumlu biçimde yapılabilir.

Bu şu anlama gelir: yeniden yapılandırmak yerine ekleme yoluyla genişletmek, zorunlu alanlar yerine opsiyonel alanlar, her iki tarafta toleranslı okuyucular. Bu şekilde tasarlanmış bir API, tek bir sürüm sıçraması olmadan yıllarca büyür — ve hedef tam olarak budur. Bir sürüm, artık uyumlu biçimde ilerleyemediğinizin itirafıdır; bunu nadiren ve bilinçli olarak yapmalısınız.

Tavsiye: Yeni sürümü son çare olarak görün ve mümkün olduğunca çok şeyi uyumlu evrimle çözün. Bedeli, uyumlu çözümün nadiren en zarif olmasıdır — miras yükü taşırsınız, opsiyonel alanlar biriktirir ve bugün farklı seçeceğiniz isimlerle yaşarsınız. Model temelden yanlış hâle geldiyse ya da bir güvenlik gereksinimi uyumsuz bir değişikliği zorunlu kılıyorsa farklı karar veririz — o zaman yeni sürüm, sözleşmeyi bulanıklaştıran bir dizi eğip bükmeden daha dürüst bir cevaptır.

Geriye dönük uyumlu genişletmek

Uyumlu evrimin aracı veri geçişindekiyle aynıdır: ekleme yoluyla büyümek, mevcut olanı asla değiştirmemek. Eski alanlar kaybolmadan yeni alanlar eklenir. Yeni parametreler opsiyoneldir ve şimdiye kadarki davranışı koruyan bir varsayılan değere sahiptir. Bir alanın değiştirilmesi gereken yerde ikisi bir süre yan yana var olur; eskisi ancak bir noktada — yeni bir sürümde — kaybolur.

İkinci yarı toleranslı okuyucudur: Her iki taraf da tanımadığını görmezden gelir. Bilinmeyen alanları atlayan ve yeni enum değerlerinde çökmeyen bir istemci, sunucunun onu kırmadan ekleme yoluyla büyümesine izin verir. Bilinmeyen girdi alanlarını hemen reddetmeyen bir sunucu, istemcilerin ileriye dönük geliştirme yapmasına olanak tanır. Taahhüt ettiğinizde katı; kabul ettiğinizde toleranslı.

Yanıt eski alan + yeni alan eski istemci yeni alanı atlar yeni istemci yeni alanı kullanır

Şema: Yeni alan eklemek, mevcut istemciler bilinmeyen alanları görmezden geldiği sürece uyumluluğu korur.

Tavsiye: Ekleme yoluyla genişletin ve her iki tarafa da tolerans yerleştirin. Bedeli, alanların birikmesi, neredeyse her şeyin opsiyonel hâle gelmesi ve API'nin zamanla sıfırdan bir tasarımın içereceğinden fazlasını taşımasıdır — bunun gelişigüzelliğe dönüşmemesi için disiplin gerekir. Çağıranlarını aynı hamlede deploy ettiğimiz tamamen dahili bir API'de farklı karar veririz — orada tolerans yalnızca bulanıklığa mal olur ve doğrudan, koordine edilmiş bir kırılma kalıcı opsiyonellikten daha temizdir.

Breaking change kaçınılmaz olduğunda

Bazen uyumlu biçimde olmaz. Model temelden değişmiştir, sözleşmedeki bir hatanın düzeltilmesi gerekir ya da bir birleştirme ekleme yoluyla ifade edilemez. O zaman — ve ancak o zaman — yeni bir sürüm doğar. Bir sürüm bir pazarlama numarası değil, bir sınırdır: Arkasında farklı, açıkça adlandırılmış bir sözleşme geçerlidir ve eski sürüm, müşteriler ona ihtiyaç duyduğu sürece dokunulmadan geçerli kalır.

Belirleyici kural: Yeni bir sürüm eskisini kırmaz. Onun yanına gelir. “Sürüm 2”yi deploy ederken “sürüm 1”i değiştiren, sürümleme yapmamış, yalnızca kırılmayı yeniden adlandırmıştır.

Tavsiye: Yeni bir ana sürümü yalnızca gerçek breaking change'ler için getirin ve her küçük uyumsuzluk için bir sürüm açmak yerine birkaçını bir araya toplayın. Bedeli, istenen kırılmaların bir sürüm sıçraması değene kadar beklemek zorunda kalması ve açtığınız her sürümün yıllarca sürüklenmesidir. İlk kararlı sürümden önceki ve açıkça kararsız olarak işaretlenmiş bir API'de farklı karar veririz — orada kırılabilir, çünkü henüz kimse üzerine inşa edebileceği bir söz almamıştır.

Sürüm bilgisi nerede tanımlanır: URL, header veya media type?

Bir sürüm gerekiyorsa, nerede görünür olacağı sorusu ortaya çıkar. Yerleşik üç yer vardır ve hiçbiri bedelsiz değildir.

YerleşimÖrnekAvantajBedelNe zaman
URL path/v2/ordersgörünür, önbelleklenebilir, test etmesi kolaysürüm bilgisi kaynak adresinin bir parçası olurherkese açık API’ler, API genelinde sürümleme
HeaderApi-Version: 2URL sürümler boyunca sabit kalırdaha az görünür; unutulabilir ve önbellek yönetiminde ek dikkat gerektirirkontrollü, dahili istemciler
Media typeAccept: …vnd.batunet.v2+jsonayrıntılı kontrol sağlar, HTTP modeline uygundurkarmaşık; araç ve yapılandırma için daha fazla iş yükü gerektirirhypermedia, ayrıntılı ve uyumlu geliştirme

Çoğu herkese açık API için URL path'teki sürüm doğru seçimdir: Görünürdür, loglarda ve önbelleklerde nettir, her araçta hemen test edilebilir ve müşteriler için açıklama gerektirmeden anlaşılırdır. Bedeli kavramsal niteliktedir — aynı kaynak kastedilse de sürüm kaynak URL'sinin parçası olur ve sürümler path'te çoğalma eğilimindedir.

Tavsiye: Herkese açık API'leri URL path üzerinden kaba taneli sürümleyin. Bedeli, kavramsal bulanıklık ve yeni bir numara çok kolay açıldığında sürümlerin çoğalma eğilimidir. İnce taneli evrimde ya da media type sürümlemenin HTTP modeline daha sadık kaldığı hypermedia API'lerde ve sunucuyu ve çağıranı birlikte kontrol ettiğiniz için bir header'ın yettiği tamamen dahili istemcilerde farklı karar veririz.

İki sürümü paralel işletmek

İkinci bir sürüm var olur olmaz iki sözleşme aynı anda çalışır — ve pahalı tuzak, bunun için iki sistem inşa etmektir. Doğru yol, çekirdekte tek bir implementasyon ve kenarda ince bir çeviridir: Bir sürüm yönlendiricisi (version router) isteği alır, dahili modele çevirir ve yanıtı her seferinde taahhüt edilen sözleşmeye geri biçimlendirir. Çekirdek sürüm bilmez; yalnızca kenar bilir.

İstemci v1 İstemci v2 Sürüm yönlendirici Çeviri Çekirdek (sürümsüz)

Şema: İş mantığının bulunduğu çekirdek sürümden bağımsız kalır. API katmanı, her sürümün sözleşmesine uygun dönüşümü yapar.

Tavsiye: Birden fazla sürümü ayrı stack'ler olarak değil, ortak bir implementasyon üzerinde çeviriler olarak işletin. Bedeli, sürüm başına bakımı yapılan bir çeviri katmanı ve her sözleşmeyi ayrı ayrı test etme yükümlülüğüdür. İki sürüm iş alanı açısından o kadar ayrışmışsa ki çeviri iki ayrı yoldan daha karmaşık hâle gelecekse farklı karar veririz — bu nadir bir durumdur ve çoğu zaman bunların bir ürünün iki sürümü değil, iki farklı ürün olduğu anlamına gelir.

Deprecation bir olay değil, bir süreçtir

Eski bir sürümü kapatmak bir son gün değil, ön hazırlık süresi olan bir akıştır. Herhangi bir şey olmadan çok önce bir duyuruyla başlar. Deprecation'ı protokolde görünür kılar — her çağrıya bu sürümün sona erdiğini ve ne zaman sona ereceğini bildiren Deprecation ve Sunset header'ları aracılığıyla. Ve telemetriye dayanır: Eski sürümü kapatmadan önce onu hâlâ kimin kullandığını bilmeniz gerekir, yoksa körlemesine kapatırsınız.

v1 v2 Duyuru v1 kapatma ikisi de aktif · Sunset header'ı Zaman

Şema: Duyuru ile kapatma arasında iki sürüm de çalışır — Sunset header'ı tarihi bildirir.

AşamaNe olurÇağıran ne görür
Duyurusona eriş erkenden bildirilirDeprecation header'ı, changelog
Paralel işletimeski ve yeni aynı anda çalışırSunset header'ı tarihi bildirir
Gözlemtelemetri kalan kullanımı kontrol ederhiçbir şey — çalışmaya devam eder
Kapatmaneredeyse hiç kullanılmadığında eski kaldırılırduyurulan tarih devreye girer

Tavsiye: Deprecation'ları erkenden duyurun, Deprecation ve Sunset header'ları aracılığıyla makine tarafından okunabilir hâle getirin ve ancak telemetri eski sürümün artık ciddi biçimde kullanılmadığını gösterdiğinde kapatın. Bedeli, eski sürümü tüm pencere boyunca işletmeye, güvence altına almaya ve test etmeye devam etmenizdir — çoktan kurtulmak istediğiniz bir sürüm aylarca yaşar. Harici kullanıcısı olmayan ya da doğrudan konuşulan küçük, bilinen bir çağıran grubuna sahip bir API'de farklı karar veririz — orada pencere kısa olabilir, çünkü geçiş tahmin edilmek yerine koordine edilir.

Sözleşmeleri müşteriden önce test etmek

En tehlikeli breaking change istenmeden yapılanıdır — kimsenin kırıcı olarak tanımadığı yeniden adlandırma. Buna karşı tek çare sözleşmenin kendisini test etmektir. Sözleşme testleri, yanıtın taahhüt edilen biçimini her değişikliğe karşı kontrol eder; tüketici güdümlü sözleşmeler (consumer-driven contracts) müşterilerin beklentilerini kaydetmesine izin verir; böylece bir kırılma yabancı production'da değil, kendi build'inizde fark edilir.

Tavsiye: Herkese açık sözleşmeyi, taahhüt edilen biçim değiştiği anda kırılan testlerle güvence altına alın. Bedeli, bakımı yapılan bir test paketi ve tüketici güdümlü sözleşmelerde çağıranlarla bir miktar koordinasyondur. Az sayıda bilinen kullanıcısı olan çok küçük, istikrarlı bir API'de farklı karar veririz — orada tam bir sözleşme testi kurgusu yerine hafif bir örnek yanıtlar seti regresyon ağı olarak yeterli olabilir.

İletişim: changelog, süreler, geçiş yolu

Müşterileri tek başına teknik kırmaz — kötü iletişim kırar. Görünür her değişikliğe, kırıcı olanları kırıcı olmayanlardan açıkça ayıran bir changelog eşlik eder. Her yeni sürüme, eskiden yeniye nasıl geçileceğini adım adım gösteren bir geçiş yolu eşlik eder. Ve her deprecation'a erkenden bildirilen ve uyulan bir süre eşlik eder. Bilinen çağıranlar ayrıca, belki kimsenin okumadığı bir header üzerinden değil, doğrudan bilgilendirilir.

Tavsiye: İletişimi sözleşmenin bir parçası olarak ele alın — changelog, geçiş kılavuzu ve güvenilir süreler. Bedeli süregelen emektir: Her değişikliğin tarif edilmesi, her sürenin takip edilmesi gerekir. Çağıranların bilindiği ve ulaşılabilir olduğu, bir ekip içindeki dahili API'lerde farklı karar veririz; orada kısa bir not yeterlidir.

Sık yapılan hatalar

İstemci sistemlerinde uyumluluk sorunlarına yol açan yaygın hatalar:

  • Bir alanı breaking change olarak tanımadan yeniden adlandırmak ya da kaldırmak — en yaygın sessiz kırılma.
  • Doğrulamayı sonradan sıkılaştırmak ve bunun “yalnızca bir düzeltme” olduğunu varsaymak — çağıran için bu bir kırılmadır.
  • “Sürüm 2”yi deploy ederken “sürüm 1”i değiştirmek — sürümleme değil, yeniden adlandırılmış bir kırılma.
  • Her küçük uyumsuzluk için yeni bir sürüm açmak; ta ki hangisinin geçerli olduğunu kimse bilmeyene kadar.
  • İki sürümü kenarda çevirmek yerine ayrı sistemler olarak inşa etmek — çifte bakım, çifte hata.
  • Telemetri olmadan kapatmak ve eski sürümü artık kimsenin kullanmadığını ummak.
  • Deprecation'ı yalnızca header'da duyurmak ve müşterilerin şaşırmasına şaşırmak.
  • Eski sürümü kalıcı bir ikinci arayüze dönüşene kadar “geçici olarak” tutmak.

Kontrol listesi

Bir ekibin her API değişikliğinden önce sorabileceği sorular. Bunlar hüküm değil, teşhis sorularıdır.

  • Mevcut bir çağıran bu değişikliği fark edebilir mi? Evetse, ne kadar küçük görünürse görünsün kırıcıdır.
  • Hedefe mevcut olanı değiştirmek yerine ekleme yoluyla ulaşılabilir mi? Uyumlu evrim neredeyse her zaman daha ucuz yoldur.
  • Yeni bir sürüm gerekiyorsa — eskisi dokunulmadan geçerli kalıyor mu? Eskisini değiştiren bir sürüm yalnızca yeniden adlandırılmış bir kırılmadır.
  • Çekirdek sürümsüz mü çalışıyor ve çeviri yalnızca kenarda mı? Aksi hâlde yakında iki sözleşme yerine iki sistemin bakımını yaparsınız.
  • Eski sürümü hâlâ kimin kullandığını telemetriden biliyor muyuz? Bu rakam olmadan körlemesine kapatırsınız.
  • Deprecation ve Sunset header'ları ayarlanmış ve süre bildirilmiş mi? Asıl kırılma sürprizdir.
  • Herkese açık sözleşmeyi otomatik olarak test ediyor muyuz? Aksi hâlde kırılmayı müşteri bizden önce öğrenir.
  • Yabancı bir ekibin tek başına izleyebileceği bir geçiş yolu var mı? Yoksa geçiş geri sorulara takılır.

Sıkça Sorulan Sorular

Uyumlu kalıyorsak sürümlere hiç ihtiyacımız var mı? İdeal durumda nadiren. İyi tasarlanmış bir API, sürüm sıçraması olmadan yıllarca ekleme yoluyla büyür. Sürümler, uyumluluğun artık yetmediği an için saklıdır — olağan geliştirme için değil.

URL path mı, header mı — hangisi doğru? Herkese açık API'ler için çoğu zaman URL path, çünkü görünür, önbelleklenebilir ve açıklama gerektirmeden test edilebilirdir. Header'lar kontrollü dahili istemcilere, media type sürümleme ise ince taneli ya da hypermedia API'lere uyar. Her yolun bedeli yukarıdaki tabloda yer alıyor; bağlamdan bağımsız bir kazanan yoktur.

Eski bir sürümü ne kadar süre işletmemiz gerekir? Telemetri onun artık ciddi biçimde kullanılmadığını gösterene kadar ve en az duyurduğunuz süre kadar. Rakam bir kurala değil, müşterilerinize bağlıdır — ama erkenden bildirilen ve sonra uyulan bir süre, tam uzunluğundan daha önemlidir.

Yeni bir zorunlu parametre breaking change midir? Evet. Mevcut, şimdiye kadar geçerli bir çağrının birden başarısız olmasına yol açan her şey kırar — yeni bir zorunlu parametre, daha katı bir doğrulama, daha küçük bir limit. Makul bir varsayılan değerle yeni ve opsiyonel olan kırmaz; yeni ve zorunlu olan kırar.

Bir müşteri belgelenmemiş bir davranışa güveniyorsa ne olur? O zaman yine de ona güvenir ve siz onu değiştirdiğinizde sistemi kırılır. Bu yüzden güvenli varsayım, gözlemlenebilen her davranışın sözleşmenin parçası olduğudur. Bu tür bağımlılıklar bir deprecation süresiyle azaltılabilir — ama zaten hiç taahhüt edilmediğini hatırlatarak değil.

İki sürüm, emek ikiye katlanmadan nasıl yürütülür? İki ayrı sistem olarak değil, kenarda ince bir çeviri katmanı olan sürümsüz bir çekirdek olarak: Çekirdek sürüm bilmez, her sürüm kendi sınırında ortak biçime çevirir. Böylece iş mantığının bakımı bir kez, yalnızca çevirininki iki kez yapılır — katlanılabilir ile katlanılamaz paralel işletim arasındaki fark tam olarak budur.

İleri okuma

Temelinde Batunet Engineering Method yatar: sözleşmeler hakkında bilinçli karar vermek, küçük ve geri alınabilir adımlarla değiştirmek, hata durumunu önceden prova etmek.


İyi bir API değişikliğini müşteri fark etmez. Yeni alanlar belirir, eskiler kalır, sürümler önceden haber verilerek sona erer — ve hiç görmediğiniz sistemler hiçbir şey olmamış gibi çalışmaya devam eder.

İlgili kavramlar ve teknolojiler

Bu alanda somut bir projeniz mi var?

Teknik rehberlerimiz yaklaşımımızı gösterir. Projenizin ihtiyaçlarını doğrudan şirket yönetimiyle değerlendirin.