İçeriğe geç
academia.sh

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. durum alanının rafta değ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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat