Ders 01 / 34
API Nedir
Bir arayüzü sözleşme yapan şey: tüketicinin yazılı olmayan varsayımları, uyumlu ve kırıcı değişimin tüketici davranışıyla tanımlanması, hoşgörülü okuyucu ile katı okuyucunun aynı değişime verdiği farklı yanıt ve sözleşmenin sahibinin kim olduğu.
İçindekiler
Önceki kurs sunucunun dışarıya bir dosya ya da bir belge verdiği durumları kurdu: insanın okuyacağı içerik. Kütüphane ödünç servisinin asıl tüketicileri ise programlardır. Şubedeki raf ekranı kitabın durumunu sorar, gece çalışan rapor işi yazar başına döküm alır, denetim betiği kayıtların biçimini sınar. Üçü de aynı ucu çağırır ve üçü de o uçtan farklı bir şey bekler.
Bu noktada ortaya çıkan kavram uygulama programlama arayüzüdür (application programming interface): bir programın başka programlara açtığı çağrılabilir yüzey. Bu ders o yüzeyin neden bir sözleşme (contract) sayıldığını ve sözleşmenin ne zaman bozulduğunu kurar.
Sözleşme, Gövdeden Fazlasıdır
Bir ucun döndürdüğü JSON gövdesine bakmak, sözleşmenin tamamını görmek değildir. Sözleşme, iki tarafın birbirinden bekleyebileceği her şeyi kapsar:
- Yüzey: hangi adresler vardır, hangi yöntemleri kabul ederler, hangi parametreleri tanırlar.
- Biçim: gövdedeki alanların adları, tipleri, zorunluluk durumları ve değer kümeleri.
- Anlam: bir alanın neyi gösterdiği.
durumalanınınraftadeğeri, kitabın fiziksel yerini mi yoksa ödünç verilebilirliğini mi bildirir? - Davranış: aynı isteğin iki kez yapılmasının sonucu, hataların hangi durum koduyla bildirildiği, sıralamanın garanti edilip edilmediği.
Bunların yalnız bir kısmı yazılır. Yazılmayan kısım da sözleşmenin parçasıdır, çünkü tüketici ona dayanarak çalışır. Bir listenin her seferinde aynı sırayla döndüğünü fark eden bir tüketici, o sırayı varsayarak kod yazar; sıra değiştiğinde arayüzün “belgelenmiş” hiçbir kısmı değişmemiş olsa da tüketici kırılır. Sözleşmenin sınırını belgenin kapsamı değil, tüketicinin bağlandığı her şey çizer.
Uyumluluk Bir Ölçüm Sorusudur
Bir değişikliğin kırıcı (breaking) olup olmadığı, değişikliğin büyüklüğüyle değil, var olan tüketicilerin o değişiklikten sonra çalışıp çalışmadığıyla tanımlanır. Bu tanım ölçülebilir: aynı tüketicileri, yayımlanan farklı sözleşme sürümlerine karşı çalıştırmak yeterlidir.
Kütüphane servisinin kitap ucu üç ayrı sürüm yayımlayabilecek biçimde yazılır.
// sunucu.mjs — kitap kaydini yayimlayan uc. SOZLESME degiskeni yayimlanan surumu secer. import { createServer } from "node:http"; const SOZLESME = process.env.SOZLESME ?? "v1"; const KAYIT = { isbn: "978-0262033848", ad: "Algoritmalara Giris", yazar: "Cormen", durum: "rafta" }; const govdeUret = () => { if (SOZLESME === "v1") return KAYIT; if (SOZLESME === "v2-ekleme") return { ...KAYIT, sayfa: 1312 }; // alan eklendi return { isbn: KAYIT.isbn, ad: KAYIT.ad, // alan adi ve tipi degisti yazar: { ad: KAYIT.yazar }, oduncDurumu: KAYIT.durum, sayfa: 1312 }; }; createServer((istek, yanit) => { yanit.sendDate = false; const govde = JSON.stringify(govdeUret()); yanit.setHeader("Content-Type", "application/json; charset=utf-8"); yanit.setHeader("Content-Length", Buffer.byteLength(govde)); yanit.writeHead(200).end(govde); }).listen(8441, "127.0.0.1");
Üç tüketici, üç ayrı okuma alışkanlığını temsil eder. Raf ekranı yalnız gereksindiği iki alanı okur. Rapor işi de az alan okur ama bir alanın tipine bağlıdır. Denetim betiği gövdeyi bütün olarak sınar ve tanımadığı alanı hata sayar.
// tuketici.mjs — uc ayri tuketici. Kullanim: node tuketici.mjs <uctermin|rapor|denetci> const rol = process.argv[2]; const kayit = await (await fetch("http://127.0.0.1:8441/kitaplar/978-0262033848")).json(); const ROLLER = { // Hosgorulu okuyucu: yalniz gereksindigi alanlari okur, tanimadigi alanlari yok sayar. uctermin: (k) => { if (typeof k.durum !== "string") throw new Error("durum alani yok"); return `raf ekrani: ${k.ad} -> ${k.durum}`; }, // Hosgorulu, ama bir alanin tipine bagli. rapor: (k) => { if (typeof k.yazar !== "string") throw new Error("yazar alani dizgi degil"); return `rapor satiri: ${k.yazar.toUpperCase()} / ${k.ad}`; }, // Kati okuyucu: sozlesmede sayilmayan her alani reddeder. denetci: (k) => { const BEKLENEN = ["isbn", "ad", "yazar", "durum"]; const fazla = Object.keys(k).filter((a) => !BEKLENEN.includes(a)); if (fazla.length) throw new Error(`beklenmeyen alan: ${fazla.join(", ")}`); return `denetim: ${k.isbn} gecerli`; }, }; try { console.log(` ${rol.padEnd(9)} OK ${ROLLER[rol](kayit)}`); } catch (e) { console.log(` ${rol.padEnd(9)} KIRIK ${e.message}`); }
#!/usr/bin/env bash # Uc sozlesme surumunu uc tuketiciyle sinar. A=http://127.0.0.1:8441/kitaplar/978-0262033848 for s in v1 v2-ekleme v2-degistirme; do SOZLESME=$s node sunucu.mjs & p=$! echo "== yayimlanan sozlesme: $s ==" printf ' govde: ' curl -s --retry 20 --retry-all-errors --retry-delay 0 --retry-connrefused "$A"; echo for rol in uctermin rapor denetci; do node tuketici.mjs $rol; done kill $p 2>/dev/null; wait $p 2>/dev/null || true done
== yayimlanan sozlesme: v1 ==
govde: {"isbn":"978-0262033848","ad":"Algoritmalara Giris","yazar":"Cormen","durum":"rafta"}
uctermin OK raf ekrani: Algoritmalara Giris -> rafta
rapor OK rapor satiri: CORMEN / Algoritmalara Giris
denetci OK denetim: 978-0262033848 gecerli
== yayimlanan sozlesme: v2-ekleme ==
govde: {"isbn":"978-0262033848","ad":"Algoritmalara Giris","yazar":"Cormen","durum":"rafta","sayfa":1312}
uctermin OK raf ekrani: Algoritmalara Giris -> rafta
rapor OK rapor satiri: CORMEN / Algoritmalara Giris
denetci KIRIK beklenmeyen alan: sayfa
== yayimlanan sozlesme: v2-degistirme ==
govde: {"isbn":"978-0262033848","ad":"Algoritmalara Giris","yazar":{"ad":"Cormen"},"oduncDurumu":"rafta","sayfa":1312}
uctermin KIRIK durum alani yok
rapor KIRIK yazar alani dizgi degil
denetci KIRIK beklenmeyen alan: oduncDurumu, sayfa
Dokuz sonuç üç kural verir.
Alan eklemek kendiliğinden uyumlu değildir. sayfa alanının eklenmesi iki tüketiciyi
etkilemedi, denetim betiğini kırdı. Sağlayıcı tarafında “yalnızca ekledim” cümlesi, tüketici
tarafında bir hata olarak göründü. Eklemenin uyumlu sayılabilmesi, tüketicilerin tanımadıkları
alanları yok saymasına bağlıdır.
Ad değiştirmek alan silmekle aynı şeydir. durum alanı oduncDurumu olarak yeniden
adlandırıldığında, raf ekranı için o alan yok olmuştur. Sağlayıcının niyeti “adı düzeltmek”
olsa da tüketicinin gördüğü şey silinmiş bir alandır.
Tip değiştirmek adı korusa bile kırıcıdır. yazar alanı yerinde durmaktadır, ama artık
bir dizgi değil bir nesnedir. Alan adına bakan bir denetim bu değişikliği yakalamaz; rapor
işi çalışma anında kırılır.
Uyumluluğun İki Yönü
Ölçüm tek bir yönü sınadı: sunucu yeni, tüketiciler eski. Bu yöne geriye dönük uyumluluk (backward compatibility) denir ve sağlayıcının yayım kararını belirleyen ölçüt budur, çünkü sunucu tüketicilerden önce güncellenir.
Ters yön de vardır ve gözden kaçar: tüketici yeni, sunucu eski. İleriye dönük uyumluluk
(forward compatibility), henüz yayımlanmamış bir sözleşmeye göre yazılmış tüketicinin eski
sunucuyla çalışabilmesidir. Kütüphane servisinde bu durum, uçbirimler merkezden önce
güncellendiğinde ortaya çıkar: yeni uçbirim sayfa alanını okumaya çalışır, eski sunucu o
alanı hiç göndermez. Alan eksik olduğunda uçbirimin çökmesi ile boş göstermesi arasındaki
fark, sözleşmenin değil tüketicinin kararıdır.
İki yön birlikte bir yayım kuralı verir: önce alanı ekleyen sunucu, sonra alanı okuyan tüketici yayımlanır; alan kaldırılırken sıra terstir. Sözleşme değişimi tek bir olay değil, iki taraf arasında sıralı bir geçiştir.
Hoşgörülü Okuyucu
Ölçümdeki denetim betiği, kırılmasına kendi kuralıyla yol açtı: gövdede sayılmayan bir alan görünce hata verdi. Bu davranışın karşıtı hoşgörülü okuyucudur (tolerant reader): tüketici yalnız gereksindiği alanları okur, tanımadığı her şeyi yok sayar.
Hoşgörülü okuma bir tüketici alışkanlığıdır ama sonucu sağlayıcıyı ilgilendirir: bir arayüz, tüketicileri hoşgörülü okuduğu ölçüde geliştirilebilir kalır. Katı okuyan tüketicilerin bulunduğu bir sistemde her ekleme sürüm atlamayı gerektirir; hoşgörülü okuyan tüketicilerin bulunduğu bir sistemde eklemeler sessizce yayılır.
Bunun ters yönde bir sınırı vardır. Hoşgörü, girdi doğrulamasına uygulanmaz. Sunucu
kendisine gelen bir gövdede tanımadığı alanları yok saydığında, tüketicinin yazım yanlışı
sessizce göz ardı edilir: oduncSuresi yerine oduncSure yazan bir istemci hata almaz,
varsayılan değerle çalışır ve yanlışı ancak sonuçtan anlar. Kural bu yüzden iki yönde
farklıdır: gönderirken kesin ol, alırken hoşgörülü ol.
Sözleşmenin Sahibi Tüketicidir
Bir arayüzün sahibi onu yayımlayan taraftır, ama sözleşmenin geçerliliğini belirleyen taraf tüketicidir. Bu ayrımın iki pratik sonucu vardır.
Birincisi, kırıcı değişikliğin maliyeti tüketici sayısıyla artar. Tek tüketicisi olan bir iç
arayüzde durum alanını yeniden adlandırmak, iki tarafı birlikte yayımlamak demektir.
Şubelerdeki uçbirimlere dağıtılmış bir arayüzde aynı değişiklik, güncellenmemiş her uçbirimin
kırılması demektir. Aynı teknik değişiklik, iki bağlamda iki ayrı karardır.
İkincisi, sözleşmenin yazılı kısmı ne kadar genişse tüketicinin yazısız varsayımlara dayanma payı o kadar azalır. Alanların tipleri, zorunlulukları ve değer kümeleri açıkça belirtilmişse, tüketici “gözlemleyerek” değil “okuyarak” bağlanır. Sıralamanın garanti edilmediği yazılıysa, sıralamaya dayanan tüketici hatalıdır. Makine okunur bir tanımın değeri buradan gelir ve bu kursun ilerleyen bölümünde ele alınır.
Özet
- Bir API’nin sözleşmesi gövde biçiminden geniştir: yüzey, biçim, anlam ve davranış birlikte sözleşmeyi kurar; tüketicinin bağlandığı yazısız varsayımlar da bu kapsamdadır.
- Bir değişikliğin kırıcı olup olmadığı, var olan tüketicilerin değişiklikten sonra çalışıp çalışmadığıyla tanımlanır ve tüketicileri yeni sürüme karşı çalıştırarak ölçülür.
- Ölçümde alan eklemek katı okuyan tüketiciyi kırdı, ad değiştirmek alanı silmekle aynı etkiyi yaptı, tip değiştirmek ise ad korunduğu hâlde çalışma anında kırılma üretti.
- Hoşgörülü okuyucu tanımadığı alanları yok sayar ve arayüzün eklemelerle geliştirilebilir kalmasını sağlar; aynı hoşgörü gelen isteklerin doğrulanmasına uygulanmaz.
- Sözleşmenin maliyeti tüketici sayısıyla artar; yazılı olmayan her ayrıntı, tüketicinin gözleme dayanarak bağlanacağı bir yüzeydir.
Sonraki Adım
Bu ders sözleşmenin ne olduğunu kurdu ama sözleşmenin biçimini açık bıraktı: kitap kaydı neden bir adresten okunuyor, neden bir yordam çağrısıyla istenmiyor, neden istemci hangi alanları istediğini söylemiyor? Aynı iş üç ayrı yaklaşımla karşılanabilir — kaynak temelli, uzak yordam çağrısı biçimli ve sorgu temelli — ve bu üç yaklaşım arasındaki fark bir üslup tercihi değildir. Sonraki ders üçünü de aynı senaryo için yazar ve aralarındaki farkı üç ölçüyle gösterir: kaç istek gitti, kaç bayt taşındı, taşınan verinin ne kadarı kullanıldı?
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.