WEB / WEB-17.02
Schemas, serialization ve API evolution
Geçerli JSON, uyumlu contract ve izinli resource erişimi nasıl ayrılır?
1. Core · Mekanizma
Hareket olmadan bütün senaryoları oku
Alan korunur
- Request hazır
Reader public liste için pageSize=2 request’ini hazırladı. Server henüz almadı; parse/schema kararı, tenant filtresi veya response sonucu oluşmadı.
- API reader
- pageSize=2 hazır; response yok
- Atlas API
- Contract v1; request yok
- Request geldi
Request server’a ulaştı; parse ve schema kararı henüz verilmedi.
- API reader
- Request hazır; UI yok
- Atlas API
- Request geldi; validation bekliyor
- Local contract
pageSize=2 integer ve 1–3 aralığındadır; örnekte permission ayrıca kabul edilmiştir. Server bu compatibility dalı için id=book-A, title=Atlas Notları, subtitle=Web rehberi response’unu hazırlar; reader henüz almadı.
- API reader
- Request hazır; UI yok
- Atlas API
- Request kabul edildi; response hazır
- Response geldi
JSON response reader’a ulaştı; old-reader schema ve alan korunumu henüz değerlendirilmedi.
- API reader
- Response geldi; old reader bekliyor
- Atlas API
- Request kabul edildi; response hazır
- Old reader
Old reader required id/title string koşullarını sağlar. Bilmediği subtitle=Web rehberi alanını preserve policy’siyle yorumlamadan korur; bu yerel contract kararı gerçek DOM render ölçümü değildir.
- API reader
- title/subtitle korundu; UI hazır
- Atlas API
- Request kabul edildi; response hazır
Rename kırılır
- Request hazır
Reader public liste için pageSize=2 request’ini hazırladı. Server henüz almadı; parse/schema kararı, tenant filtresi veya response sonucu oluşmadı.
- API reader
- pageSize=2 hazır; response yok
- Atlas API
- Contract v1; request yok
- Request geldi
Request server’a ulaştı; parse ve schema kararı henüz verilmedi.
- API reader
- Request hazır; UI yok
- Atlas API
- Request geldi; validation bekliyor
- Local contract
pageSize=2 integer ve 1–3 aralığındadır; örnekte permission ayrıca kabul edilmiştir. Server bu compatibility dalı için id=book-A, heading=Atlas Notları; title yok response’unu hazırlar; reader henüz almadı.
- API reader
- Request hazır; UI yok
- Atlas API
- Request kabul edildi; response hazır
- Response geldi
JSON response reader’a ulaştı; old-reader schema ve alan korunumu henüz değerlendirilmedi.
- API reader
- Response geldi; old reader bekliyor
- Atlas API
- Request kabul edildi; response hazır
- Old reader
Response JSON olarak okunabilir ama required title yoktur; heading onu yerine getirmez. Old reader sonucu reddeder ve yeni book UI verisi hazırlamaz; eski title başarı gibi tekrar kullanılmaz.
- API reader
- title eksik; UI yok
- Atlas API
- Request kabul edildi; response hazır
Unknown reddi
- Request hazır
Reader public liste için pageSize=2, display=wide request’ini hazırladı. Server henüz almadı; parse/schema kararı, tenant filtresi veya response sonucu oluşmadı.
- API reader
- pageSize=2, display=wide hazır; response yok
- Atlas API
- Contract v1; request yok
- Request geldi
Request server’a ulaştı; parse ve schema kararı henüz verilmedi.
- API reader
- Request hazır; UI yok
- Atlas API
- Request geldi; validation bekliyor
- Closed request
Closed request kuralı bilinmeyen display alanını açıkça reddeder; business read çalışmaz.
- API reader
- Request hazır; UI yok
- Atlas API
- Schema reddi; error hazır
- Hata geldi
Schema rejection reader’a ulaştı; valid response listesi veya UI book oluşmadı.
- API reader
- Schema error geldi; UI yok
- Atlas API
- Schema reddi; error hazır
İkinci sayfa
- Continuation hazır
İlk sayfa A/B daha önce alınmıştır; reader cursor-A ile aynı snapshot’ın ikinci sayfasını ister.
- API reader
- cursor-A request hazır
- Atlas API
- snapshot-A; C kalan; request yok
- Cursor geldi
Server continuation request’ini teslim aldı; cursor bağı ve resource policy henüz pending.
- API reader
- cursor-A request hazır
- Atlas API
- cursor-A geldi; binding bekliyor
- Local paginator
Snapshot/filter/order bağı ile örnekteki permission koşulu sağlanır; C içeren terminal response hazırlanır.
- API reader
- cursor-A request hazır
- Atlas API
- C hazır; nextCursor yok
- Son sayfa geldi
C response’u reader’a ulaştı; nextCursor yokluğu bu seçilmiş contract’ta liste sonunu bildirir.
- API reader
- C alındı; nextCursor yok; tamam
- Atlas API
- C hazır; nextCursor yok
ROLLER · STATE · VERİ AKIŞI
JSON bir değer modeli taşır
Atlas kitap listesi önce uygulamada bir object’tir, sonra UTF-8 JSON text olarak serialize edilir; karşı uç text’i parse ederek yeni bir değer ağacı oluşturur. Bu iki object aynı bellek nesnesi değildir. JSON object alanları anlamsal olarak sıralı değildir; array sırası ise anlam taşır. Top-level yalnız object olmak zorunda değildir. String, number, boolean ve null farklı türlerdir: "2" ile 2 aynı schema sonucunu vermez. Date, class metodu veya database bağlantısı JSON’un değer türlerinden değildir.
Alan yokluğu ile alanın null olması özellikle migration sırasında ayrılır. Seçtiğimiz response’ta subtitle optional ve string-or-null’dır; yoksa client bu kitabın subtitle bilgisinin gönderilmediğini bilir, null ise bilinen boş değeri görür. Native JavaScript serializer object içindeki undefined alanı atabilir; bu, JSON’un her dilde böyle davrandığı anlamına gelmez. Büyük integer ID’leri string tutuyoruz: number üzerinden gidip sonradan string yapmak kaybolmuş hassasiyeti geri getirmez. Aynı isimli JSON member’ların davranışı parser’a göre değişebildiğinden üretici benzersiz isim üretir.
Schema hangi soruyu cevaplar?
Request schema pageSize’ın integer ve 1–3 arasında olduğunu, cursor’ın optional string olduğunu söyler. Response schema books array’inin id ve title gerektirdiğini tanımlar. Bunlar parsing’den sonraki structural kontrollerdir; kullanıcı hangi tenant’ın kitabını okuyabilir sorusu burada çözülmez. JSON Schema’da properties yazmak o alanı required yapmaz; additionalProperties varsayılanı da otomatik kapalı değildir. Fixture’ın request’i unknown alanı reddeder, response okuyucusu unknown alanı korur. Bu iki yönde aynı reject kuralını kullanmak şart değildir.
OpenAPI request/response media ve schema’ları bir arada tarif eder; belgeyi yayınlamak runtime validator çalıştırmak değildir. Burada incelenen current edition 3.2.1’dir ve schema dialect 2020-12 tabanlıdır; older 3.0 nullable alışkanlığını sessizce taşımıyoruz. openapi spec sürümünü, info.version belge sürümünü, /v1 business contract’ını ve deploy build numarasını ayrı okuruz. Artifact yalnız seçilmiş schema fragment’ları gösterir; full OpenAPI description veya bütün JSON Schema keyword’lerini yürüttüğünü iddia etmez.
Evolution ile pagination birlikte düşünülür
v1 title:string alanını koruyarak v1.1 response’a subtitle eklemek, unknown response alanını koruyan reader için uyumludur. Aynı v1’de title’ı heading olarak yeniden adlandırmak remove-and-add etkisidir; eski reader’ın title beklentisi kırılır. Bu fixture’ın major version’ı URI ile seçilir; bu bir ürün kararıdır, HTTP bütün API’leri bu yönteme zorlamaz. Uyumluluk yalnız JSON’un parse olması değildir: eski client derleniyor mu, wire türü aynı mı, eski kullanıcı aynı iş anlamını görüyor mu diye üç ayrı soru sorulur.
Liste baştan paginated tanımlanır. Tenant filtresinden sonra sabit snapshot’taki A, B, C kitapları id sırasına alınır; pageSize=2 ilk iki kitabı ve opaque cursor-A’yı döndürür, ikinci sayfa C ile biter. Cursor bu seçilmiş snapshot, filter ve order’a bağlı yerel continuation referansıdır; kitap okuma izni değildir. Az item dönmesi tek başına son sayfa kanıtı sayılmaz; bu contract’ta nextCursor yokluğu bitiştir. Canlı listede insert/delete, stable tie-breaker, snapshot ömrü ve cursor expiry ayrı tasarlanır; üç sabit kayıt bunları otomatik çözmez.
2. Red · Güven ve etki
Hareket olmadan bütün senaryoları oku
Request field
- Üretici ve reader rolü ayrıldı
Request profili pageSize ve cursor dışında alan kabul etmez. display=wide içeren request row’u bu closed contract’ın negatif örneğidir.
- Contract değişikliği
- Unknown request=reject
- Schema ve reader policy
- Schema gate bekliyor
- Consumer kararı
- Consumer kabul etmedi
- Syntax ile schema koşulu ayrıldı
pageSize=2 uygun olsa da display alanı additionalProperties=false ile uyuşmaz. Bir doğru alan diğer alanların kabulünü sağlamaz.
- Contract değişikliği
- pageSize=2
- Schema ve reader policy
- Shape inceleniyor
- Consumer kararı
- Kabul bekliyor
- Contract uyuşmazlığı belirlendi
requestRows unknown-field için expected=false bildirir. Policy reject’tir; bilinmeyen alanı sessiz silip aynı request’i kabul etme olarak gösterilmez.
- Contract değişikliği
- Known contract mismatch
- Schema ve reader policy
- Expected=false
- Consumer kararı
- Consumer gate kapalı
- Dönüşüm policy’si açık bırakıldı
Bu contract request unknown alanlarını reddederken response unknown alanlarını korur. İki yönün aynı normalization policy’sine sahip olduğu varsayılmaz.
- Contract değişikliği
- Request/response policy ayrı
- Schema ve reader policy
- Sessiz veri kaybı yok
- Consumer kararı
- Uyumsuz branch ayrı
- Version etiketi kararı değiştirmedi
contractVersion=v1 ve documentVersion=1.1 belgeleri tanımlar. Bu etiketler reddedilen shape için otomatik kabul veya business permission oluşturmaz.
- Contract değişikliği
- Versions: v1 / 1.1
- Schema ve reader policy
- Shape mismatch retained
- Consumer kararı
- Permission ayrı
- Consumer beklentisi sınırda korundu
Ret gerekçesi closed request contract’tır. Bu sonuç actor’a ait tenant izninin reddedildiğini veya normal iki sayfanın bozulduğunu tek başına söylemez.
- Contract değişikliği
- Contract failure known
- Schema ve reader policy
- Ret nedeni sınırlı
- Consumer kararı
- Yanlış kabul yok
Title rename
- Üretici ve reader rolü ayrıldı
Eski reader id ve title alanlarını zorunlu bekler. renamed response, id=book-A ve heading=Atlas Notları içerir; title alanı bulunmaz.
- Contract değişikliği
- Required: id, title
- Schema ve reader policy
- Schema gate bekliyor
- Consumer kararı
- Consumer kabul etmedi
- Syntax ile schema koşulu ayrıldı
heading string olabilir ve JSON okunabilir. Ancak yeni field’ın bulunması eski required title alanının eksikliğini gidermez.
- Contract değişikliği
- heading present; title absent
- Schema ve reader policy
- Shape inceleniyor
- Consumer kararı
- Kabul bekliyor
- Contract uyuşmazlığı belirlendi
compatibilityRows renamed için expected=false bildirir. Unknown response field’larını preserve etmek, zorunlu title yokluğunu geçerli kılmaz.
- Contract değişikliği
- Known contract mismatch
- Schema ve reader policy
- Expected=false
- Consumer kararı
- Consumer gate kapalı
- Dönüşüm policy’si açık bırakıldı
Normal response’ta subtitle eklenmesi title’ı silmediği için kabul edilebilir. Additive field ile required field rename aynı compatibility değişikliği değildir.
- Contract değişikliği
- Request/response policy ayrı
- Schema ve reader policy
- Sessiz veri kaybı yok
- Consumer kararı
- Uyumsuz branch ayrı
- Version etiketi kararı değiştirmedi
contractVersion=v1 ve documentVersion=1.1 belgeleri tanımlar. Bu etiketler reddedilen shape için otomatik kabul veya business permission oluşturmaz.
- Contract değişikliği
- Versions: v1 / 1.1
- Schema ve reader policy
- Shape mismatch retained
- Consumer kararı
- Permission ayrı
- Consumer beklentisi sınırda korundu
Ret gerekçesi required title’ın kaybıdır. Bu sonuç bütün yeni optional alanların yasak olduğu anlamına gelmez; preserve modu yalnız tanınmayan alanı yorumlamadan tutar.
- Contract değişikliği
- Contract failure known
- Schema ve reader policy
- Ret nedeni sınırlı
- Consumer kararı
- Yanlış kabul yok
VARSAYIM · SINIR · KONTROL
Format kabulünden yanlış sonuç çıkarmak
Bir request parse edildiğinde yalnız text’in seçilen parser tarafından okunabildiği öğrenilir. Schema geçtiğinde pageSize ve cursor şeklinin kabul edildiği öğrenilir. Bu iki olumlu sonuç tenant bağını, subject’in read action’ını veya cursor’ın hâlâ geçerli snapshot’a ait olduğunu kanıtlamaz. Riskli varsayım, bütün yeşil kutuları tek bir "valid request" etiketine sıkıştırmaktır. Artifact bu nedenle parse, schema, continuation ve business permission sonuçlarını ayrı ledger alanları olarak tutar; reddin hangi aşamada olduğunu reader görebilir.
Unknown field davranışı görünmeyen veri kaybı yaratabilir. Yeni response’ta subtitle bulunurken adapter yalnız id/title’ı kopyalayıp original’ı atarsa sonraki serialize işleminde subtitle yok olur. Bu veri kaybı JSON veya schema’nın zorunlu sonucu değildir; adapter’ın seçtiği dönüşümdür. Fixture’ın preserve modu extra alanı round trip’te tutar; closed request ise unknown alanı açık hata ile reddeder. Her iki policy de bilinçli olabilir, ama sessizce preserve yazıp discard davranmak compatibility sözleşmesini bozar.
Küçük değişiklik büyük iş anlamını bozabilir
Eski client boş books gördüğünde bütün arşivin boş olduğunu düşünüyorsa sonradan pagination eklemek yalnız yeni field eklemek değildir. Kullanıcı ilk sayfayı görüp eksik listeyi tam sanabilir. Title’ın türünü string’den object’e çevirmek de JSON geçerli kaldığı hâlde eski UI’ı bozar. Compatibility tablosunda bu yüzden required isim, wire türü, alan korunumu ve collection’ın tamamlandığı bilgisi ayrı değerlendirilir; hangi eski beklentinin kırıldığı açıkça gösterilir.
Opaque cursor okunamıyor diye authenticated sayılmaz. Continuation bilgisi doğru olsa bile her sayfanın resource erişimi güncel policy’ye göre değerlendirilmeli; cached result aynı tenant ve filter bağını taşımalıdır. Sadece page count veya nextCursor varlığına bakarak izin sonucu çıkarılmaz. Sabit fixture’daki başarılı iki sayfa yalnız seçilen üç kayıt için kanıttır; concurrent update, storage transaction veya cursor imza uygulaması hakkında sonuç üretmez.
3. Blue · Güvenli geliştirme ve savunma
Hareket olmadan bütün senaryoları oku
Null ve absence
- Alan sözleşmesi incelendi
Book schema’sı subtitle için string veya null kabul eder; alan required değildir. title ise required string’dir. Optional olmak ve null kabul etmek farklı koşullardır.
- Contract gözlemi
- subtitle: string | null
- Reader/page karşılaştırması
- title: required string
- İnceleme sonucu
- Reader sonucu bekliyor
- Null response row’u seçildi
null-subtitle response id ve title’ı korur, subtitle=null içerir. Bu açık null değeri, producer’ın alanı hiç göndermediği durumla aynı representation değildir.
- Contract gözlemi
- subtitle present: null
- Reader/page karşılaştırması
- Required fields present
- İnceleme sonucu
- Round trip incelenmedi
- Uyum sonucu schema’ya bağlandı
Bu row için expected=true’dur. Null kabulü schema’da açık olduğu için sonuç olumlu; reader’ın bütün bilinmeyen alanları anladığı sonucu çıkarılmaz.
- Contract gözlemi
- Expected=true
- Reader/page karşılaştırması
- Null allowed explicitly
- İnceleme sonucu
- Interpretation scope sınırlı
- Eski reader preserve modu okundu
oldReaderSchema subtitle’ı tanımlamaz ama additionalProperties=true kullanır. oldReaderUnknownFields alanı, subtitle’ın yorumlanmadan korunacağını söyler.
- Contract gözlemi
- Old reader: id/title
- Reader/page karşılaştırması
- subtitle preserved
- İnceleme sonucu
- Subtitle meaning not inferred
- Sessiz field kaybı kontrol edildi
Reader yalnız id/title’ı yeni object’e kopyalayıp original alanları atarsa preserve sözleşmesi bozulur. Kabul edilen unknown field ile round trip’te korunan field ayrı gözlenmelidir.
- Contract gözlemi
- Acceptance ≠ preservation
- Reader/page karşılaştırması
- Round trip evidence gerekli
- İnceleme sonucu
- Silent discard kabul edilmez
- İnceleme sonucu açık tutuldu
Contract, null ve absence ayrımını tanımlar; eski reader subtitle’ı yorumlamaz. Bu bilgi runtime’da tam schema validator veya bütün client’ların çalıştığı kanıtı değildir.
- Contract gözlemi
- Null acceptance known
- Reader/page karşılaştırması
- Preserve contract known
- İnceleme sonucu
- All clients unobserved
Cursor bağı
- Sayfa context’i seçildi
Profile snapshot-A, tenant-A ve id ASC sıralamasını seçer. records içinde tenant-B kaydı da vardır; continuation değerlendirmesi tenant filtresinden ayrı okunamaz.
- Contract gözlemi
- snapshot-A / tenant-A
- Reader/page karşılaştırması
- Order: id ASC
- İnceleme sonucu
- Page sonuçları bekliyor
- İlk sayfa kaydı okundu
pageSize=2 isteğine book-A ve book-B gelir, nextCursor=cursor-A bulunur. İlk iki kayıt bütün collection’ın tamamı diye raporlanmaz.
- Contract gözlemi
- Page 1: A, B
- Reader/page karşılaştırması
- nextCursor=cursor-A
- İnceleme sonucu
- Collection incomplete
- Cursor ledger bağları eşleştirildi
cursor-A snapshot-A, tenant-A, id ASC ve nextIndex=2 taşır. Cursor yalnız devam konumunu seçer; ayrıca resource permission vermez.
- Contract gözlemi
- Cursor context matched
- Reader/page karşılaştırması
- nextIndex=2
- İnceleme sonucu
- Cursor ≠ permission
- Terminal sayfa sonucu ayrıldı
İkinci sayfada yalnız book-C vardır ve nextCursor yoktur. Bu bitiş sonucu verilen snapshot’ın üç tenant-A kaydı için geçerlidir, başka snapshot için değil.
- Contract gözlemi
- Page 2: C
- Reader/page karşılaştırması
- nextCursor absent
- İnceleme sonucu
- Selected snapshot complete
- Filter ve permission kanıtı ayrıldı
tenant-B kaydının bu sayfalarda bulunmaması filter sonucudur. permissionDeclared=true ise ayrı bir önkoşuldur; cursor’ın opaque görünmesi authentication kanıtı değildir.
- Contract gözlemi
- Tenant filter known
- Reader/page karşılaştırması
- Permission declared separately
- İnceleme sonucu
- Opaque ≠ authenticated
- Snapshot kapsamı korundu
Bu iki sayfa sabit snapshot üzerinde sonuç verir. Concurrent update, cursor signature veya storage transaction davranışı için yeni kanıt gerekir; terminal sayfa bunları kanıtlamaz.
- Contract gözlemi
- Fixed snapshot only
- Reader/page karşılaştırması
- Concurrent storage unobserved
- İnceleme sonucu
- Completion bounded
UYGULAMA · GÜVENLİK KONTROLÜ · DOĞRULAMA
Üretici ve reader policy’sini birlikte yaz
Her field için isim, wire type, required/optional, null kabulü, default ve unknown-field policy yazılır. Producer title’ı hâlâ üretirken reader subtitle’ı tanımadan koruyabilir; bu round-trip contract açıkça test edilir. Request’te closed schema tercih edildiğinde bilinmeyen alan için anlaşılır hata dönülür; normalize ederken sessiz silme default değildir. Number domain’i, string boyutu ve collection limit’i parser sınırlarıyla birlikte belirlenir; JSON’un number grammar’ı business ölçü birimini veya hassasiyeti kendiliğinden garanti etmez.
Regression listesi eski request/new server ile yeni response/old reader’ı ayrı çalıştırır. Aynı normal book kaydıyla subtitle ekleme başarılı, title rename başarısız ve null subtitle açık kabul olmalıdır. Document version artması bu sonuçların yerine geçmez. Schema keyword’lerini anlayan validator seçilir ve supported dialect pin edilir; code generator çıktısı ile gerçek runtime response karşılaştırılır. Generated client’ın enum veya strict deserializer tercihleri de compatibility review’e girer.
Sayfanın sınırı ile iznin sınırını ayır
Pagination contract’ında default/max page size, sıralama tie-breaker’ı, nextCursor bitiş anlamı ve cursor’a bağlı filter/order açıklanır. Seçtiğimiz fixture in-memory sabit snapshot’tır; tenant filter pagination’dan önce uygulanır ve cursor-A sadece ikinci sayfanın başlangıcını seçer. Aynı continuation ile filter değişirse listeden tahminî yeni sayfa üretmek yerine bağ uyuşmazlığı açık hata olur. Token expiry ve snapshot kaybı client’a yeniden başlama davranışıyla anlatılır; gerçek storage implementation burada verilmiş sayılmaz.
Blue evidence yalnız schema-pass sayısı değildir. Round trip’te alanların korunması, terminal cursor’ın yokluğu, eski UI’ın title okumaya devam etmesi ve her sayfa için ayrı policy sonucu gözlenir. Daha büyük sistemlerde cache key, cancellation, timeout ve authorization değişikliğinin continuation’a etkisi de incelenir. Sahne request ve response arrival anlarını server’daki local validator/paginator kararlarından ayırır. JSON text’in parse edilmesi ise continuation bağının ve business permission’ın doğrulandığı anlamına gelmez.
ŞİMDİ VAKAYA UYGULA
Yeni alan veya cursor hangi eski beklentiyi korumak zorunda?
Request unknown alanlarını reddeder, response unknown alanlarını korur. Pagination sabit tenant/snapshot context’inde ilerler; shape ve continuation permission yerine geçmez.
Vakadaki API contract’ı ile browser’ın okuyabildiği representation’ı ayrı incele. Envelope, data, error ve resource permission için hangi gözlemin yeterli olduğunu tartış.
Bağlı vaka dosyasını aç ↗ÖRNEĞİ BİRLİKTE OKUYALIM
Atlas API contract ve continuation ledger
Bir alan seç; hangi sonucu desteklediğini ve nerede yetersiz kaldığını incele.
Ham kaydı ve alan açıklamalarını oku
{
"profile": {
"specEdition": "OpenAPI 3.2.1",
"schemaDialect": "https://json-schema.org/draft/2020-12/schema",
"contractVersion": "v1",
"documentVersion": "1.1",
"snapshot": "snapshot-A",
"tenant": "tenant-A",
"order": "id ASC",
"unknownRequest": "reject",
"unknownResponse": "preserve",
"permissionDeclared": true
},
"requestSchema": {
"type": "object",
"properties": {
"pageSize": {
"type": "integer",
"minimum": 1,
"maximum": 3
},
"cursor": {
"type": "string"
}
},
"required": [
"pageSize"
],
"additionalProperties": false,
"$schema": "https://json-schema.org/draft/2020-12/schema"
},
"bookSchema": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"subtitle": {
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"title"
],
"additionalProperties": true,
"$schema": "https://json-schema.org/draft/2020-12/schema"
},
"records": [
{
"id": "book-A",
"title": "Atlas Notları",
"tenant": "tenant-A"
},
{
"id": "book-B",
"title": "Ağ Defteri",
"tenant": "tenant-A"
},
{
"id": "book-C",
"title": "HTTP Notları",
"tenant": "tenant-A"
},
{
"id": "other-book",
"title": "Başka Arşiv",
"tenant": "tenant-B"
}
],
"cursorLedger": {
"cursor-A": {
"snapshot": "snapshot-A",
"tenant": "tenant-A",
"order": "id ASC",
"nextIndex": 2
}
},
"pages": [
{
"request": {
"pageSize": 2
},
"response": {
"books": [
{
"id": "book-A",
"title": "Atlas Notları"
},
{
"id": "book-B",
"title": "Ağ Defteri"
}
],
"nextCursor": "cursor-A"
}
},
{
"request": {
"pageSize": 2,
"cursor": "cursor-A"
},
"response": {
"books": [
{
"id": "book-C",
"title": "HTTP Notları"
}
]
}
}
],
"compatibilityRows": [
{
"case": "normal",
"response": {
"id": "book-A",
"title": "Atlas Notları",
"subtitle": "Web rehberi"
},
"expected": true,
"unknownMode": "preserve"
},
{
"case": "renamed",
"response": {
"id": "book-A",
"heading": "Atlas Notları"
},
"expected": false,
"unknownMode": "preserve"
},
{
"case": "null-subtitle",
"response": {
"id": "book-A",
"title": "Atlas Notları",
"subtitle": null
},
"expected": true,
"unknownMode": "preserve"
}
],
"requestRows": [
{
"case": "normal",
"value": {
"pageSize": 2
},
"expected": true
},
{
"case": "unknown-field",
"value": {
"pageSize": 2,
"display": "wide"
},
"expected": false
},
{
"case": "wrong-type",
"value": {
"pageSize": "2"
},
"expected": false
},
{
"case": "integer-number",
"value": {
"pageSize": 2.0
},
"expected": true
},
{
"case": "fractional",
"value": {
"pageSize": 2.5
},
"expected": false
}
],
"jsonFixtures": {
"text": "{\"id\":\"book-A\",\"title\":\"Atlas Notları\",\"subtitle\":null}",
"largeId": "9007199254740993",
"nullDistinctFromAbsent": true,
"duplicateNamesProducerForbidden": true
},
"boundaries": {
"schemaGrantsPermission": false,
"cursorGrantsPermission": false,
"actualFullValidator": false,
"concurrentStorage": false
},
"oldReaderSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"id",
"title"
],
"additionalProperties": true
},
"oldReaderUnknownFields": "preserve without interpreting subtitle"
}- requestSchema
- Seçilmiş closed request kuralları; bütün validator değil.
- bookSchema
- Current producer’ın book schema’sı; subtitle string veya null olabilir.
- pages
- Tenant filtresi sonrası sabit snapshot’ın iki sayfası.
- compatibilityRows
- Alan ekleme, rename ve null için eski reader beklentisi.
- cursorLedger
- Opaque alias’ın local snapshot/filter/order continuation bağı.
- oldReaderSchema
- Eski reader yalnız id/title bilir; unknown subtitle’ı yorumlamadan korur.
Inert schema fragment’ları ve sabit in-memory kayıtlar kullanılır. JSON serialization ve contract kararları, tam OpenAPI/JSON Schema validator veya gerçek storage implementation kanıtı değildir.
İki yanlış kanı
JSON parse olduysa request geçerlidir.
Parse yalnız syntax/değer üretir; schema, continuation ve resource policy ayrı kararlardır.
Yeni response alanı her eski client için uyumludur.
Reader’ın reject/preserve/discard davranışı ve round-trip contract kontrol edilmeden bu sonuç çıkarılmaz.
SIRA SENDE
Bu hikâyeyi sen çöz.
Sonucu tahmin et, kanıtın sınırını bul ve nedenini kendi cümlenle anlat.
Request içindeki pageSize değeri "2" string’i, fakat sözleşme integer istiyor. Input kabul edilir mi?
- Evet. Sayı gibi görünen bütün JSON string’leri integer’dır.
- Hayır. wrong-type sonucu expected=false.
Gerekçeli cevabı oku
Hayır. wrong-type sonucu expected=false. — Bu schema "2" string’ini sessizce integer’a dönüştürmez. Hem type hem size sınırları sağlanmalıdır.
Eski reader yeni subtitle alanıyla karşılaşınca bu compatibility policy’si ne ister?
Dersten seçilen artifact alanları; öğretim örneği
- oldReaderSchema.additionalProperties
- true
- oldReaderUnknownFields
- preserve without interpreting subtitle
- compatibilityRows[0]
- {"case":"normal","response":{"id":"book-A","title":"Atlas Notları","subtitle":"Web rehberi"},"expected":true,"unknownMode":"preserve"}
- Alan korunur; eski reader ona yeni bir anlam yüklemez.
- Bütün unknown alanlar her yönde otomatik silinir.
Gerekçeli cevabı oku
Alan korunur; eski reader ona yeni bir anlam yüklemez. — additionalProperties=true ve preserve policy’si sessiz veri kaybını önler. Request tarafındaki strict policy ayrı bir sözleşmedir.
cursor-A snapshot, tenant ve order taşıyor. Neden bu continuation bilgisi resource erişim izni değildir? subtitle=null neden alanın bulunmamasıyla aynı değildir?
Gerekçeli cevabı oku
Cursor hangi kayıt sırasından devam edileceğini belirler. Güncel tenant/resource izni yine ayrıca doğrulanmalıdır. Book schema subtitle=null değerine izin verir; absent ise alanın hiç bulunmamasıdır. Consumer bu farkı sözleşmesine göre korumalıdır. Bu örnek tam JSON Schema validator veya concurrent storage çalıştırmaz.
□ Cursor’ı erişim izni sağlayan capability saymadım.
□ Null değeri ile alanın bulunmamasını ayırdım.
Uygulama konsolunu aç · request / response / browser
Request, URL, cookie ve DOM örneklerini ayrıca aç
Kaynaklar ve kapsam
- RFC 8259 — JSON§2 grammar; §4 objects and unique names · §6 number interoperability; §8.1 UTF-8; §9 parsers; §10 generators
- OpenAPI Specification 3.2.1§4.2.1 info.version; §4.24 Schema Object and §4.24.7 dialect · §4.1 OpenAPI Object openapi field
- JSON Schema — Object referenceProperties; Required Properties; Additional Properties
- Google AIP-180 — Backwards compatibilityGuidance: source/wire/semantic compatibility; Adding components; Removing or renaming components
- Google AIP-158 — PaginationGuidance: page_size/next_page_token; Opacity; Backwards compatibility