Bulk, Batch ve Asenkron API'ler: Toplu İşlem, Kısmi Başarı, Webhook mi Polling mi ve Rate Limit Contract'ı
Toplu bir API'nin contract'ı boyut sınırını, hangi hatanın bütün isteği hangisinin tek satırı reddettiğini, kısmi başarının nasıl raporlandığını, sonucun nasıl bildirildiğini ve kotayı açıkça yazar. Bookstore'da okulların toplu siparişini satır bazlı bir raporla 201 olarak, allOrNothing ile 422 olarak, Prefer: respond-async ile LRO olarak tasarlıyor, webhook'u contract'a ekliyor ve RateLimit header taslağıyla 429'u gerçek yanıtlarla görüyoruz.
Sürüm notu: Bu yazıdaki kodlar C# 14 ve .NET 10 (ASP.NET Core 10.0.15) ile derlenip denenmiştir; HTTP örnekleri bu uygulamanın gerçek yanıtlarıdır, OpenAPI 3.2 dokümanı Redocly CLI 2.78.0 ve Spectral 6.17.1 ile lint edilmiştir.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore'un (bir online kitapçı) kurumsal müşterisi Lakeside School, dönem başında okuma listesini toplu sipariş olarak gönderiyor. Gerçek listeler 500 satıra kadar çıkıyor; burada yedi satırlık kısa bir örnek var. Nevin Hanım'ın sistemi listeyi yeni toplu sipariş endpoint'ine yolluyor:
$ cat batch.json
{"unitId":"main-campus","lines":[
{"isbn":"9780451524935","quantity":15},
{"isbn":"9780060850524","quantity":10},
{"isbn":"9780441172719","quantity":30},
{"isbn":"9780743273565","quantity":12},
{"isbn":"9780000000002","quantity":5},
{"isbn":"9780451524935","quantity":5},
{"isbn":"9780261102217","quantity":18}
]}
$ curl -s -i -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-2026-11-reading-list"' --data @batch.json http://127.0.0.1:52318/institutions/lakeside-school/order-batches | tee batch-created.txt | grep -v '^{'
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Date: Sat, 14 Nov 2026 23:29:06 GMT
Server: Kestrel
Content-Language: en
Location: /institutions/lakeside-school/order-batches/01a1dc64-a869-7aa4-8c17-eadef77b3831
Transfer-Encoding: chunked
Api-Version: 2026-09-01
Deprecation: @1794700800
Sunset: Mon, 17 May 2027 00:00:00 GMT
Link: <https://api.example.com/docs/versions/2026-09-01>; rel="deprecation"; type="text/html"
RateLimit-Policy: "batches";q=5;w=60
RateLimit: "batches";r=4;t=60
$ tail -1 batch-created.txt | jq -c '{orderId, acceptedLines, rejectedLines}, (.results[] | select(.status == "Rejected") | {line, isbn, type: .problem.type, detail: .problem.detail})'
{"orderId":"01a1dc64-a869-7b66-a998-7fa62adae003","acceptedLines":4,"rejectedLines":3}
{"line":3,"isbn":"9780441172719","type":"https://api.example.com/problems/insufficient-stock","detail":"Only 14 copies of Dune are available."}
{"line":5,"isbn":"9780000000002","type":"https://api.example.com/problems/not-found","detail":"Nothing exists at /books/9780000000002."}
{"line":6,"isbn":"9780451524935","type":"https://api.example.com/problems/validation-failed","detail":"Fix the fields listed in errors."}
Yedi satırın üçü reddedildi, ama yanıt 201 Created. Dört soru: Üç satırı reddedilmiş bir istek için 201 doğru mu, yoksa 207 Multi-Status, 400 ya da 422 mi olmalıydı? İstemci hangi satırların sipariş edildiğini nereden anlıyor? 6. satır neden reddedildi? Header'lardaki RateLimit satırı ne anlatıyor?
Neden Ayrı Bir Bulk Endpoint?
Toplu sipariş endpoint'i yokken okulların entegrasyonu listeyi satır satır gönderiyordu: 500 satır, 500 ayrı istek. Her istek ayrı bir authentication, ayrı bir transaction ve ayrı bir ağ gidiş-dönüşü demek; tek bir okulun dönem başı döngüsü bütün API'yi yavaşlatıyordu. Üstelik istek 312'de kopan bir döngünün nerede kaldığını kimse bilmiyordu. Bulk endpoint bu döngüyü server'a taşıyor ve sonucu tek bir rapor olarak dönüyor.
Bulk tasarımın ilk kararı boyut sınırı. Bookstore'da bir toplu sipariş en fazla 500 satır alıyor ve bu sınır contract'ta yazılı (BS-70). Google'ın AIP'lerinden (API Improvement Proposals; Google'ın numaralı API tasarım kuralları) 233 numaralı olan, batch create'te sabit bir sınır koymaz ama sınırın dokümante edilmesini ister. İkinci karar, hangi hataların bütün isteği reddedeceği. Bookstore'da kural şu (BS-71): şemaya uymayan bir istek bütünüyle 400 alıyor, iş kurallarına takılan satırlar ise tek tek raporlanıyor. Bozuk bir JSON ya da sıfır adetli bir satır, istemcinin kodunda bir hata demek; onu düzeltmeden göndermenin anlamı yok. Stokta olmayan bir kitap ise istemcinin bilemeyeceği bir durum.
$ jq -n '{unitId: "main-campus", lines: [range(501) | {isbn: "9780441172719", quantity: 1}]}' | curl -s -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-too-long"' --data @- http://127.0.0.1:52318/institutions/lakeside-school/order-batches | jq -c '{status, errors}'
{"status":400,"errors":{"lines":["out-of-range"]}}
$ jq '.lines[1].quantity = 0' batch.json | curl -s -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-zero"' --data @- http://127.0.0.1:52318/institutions/lakeside-school/order-batches | jq -c '{status, errors}'
{"status":400,"errors":{"lines[1].quantity":["out-of-range"]}}
Validation hatasının anahtarı, 04. yazıdaki kuralla request'in JSON yolu: lines[1].quantity, sıfırdan başlayan indeksle ikinci satır. Satır raporunda ise numaralar 1'den başlıyor, çünkü raporu okuyan çoğu zaman bir insan ve "6. satır" Excel'deki satırla eşleşmeli. İki numaralandırmanın farklı olması bir tutarsızlık gibi görünüyor ama bilinçli; contract ikisini de açıkça yazıyor. Toplu bir dosyayı staging tablosuna alıp satır bazlı bir hata dosyası üretmenin veritabanı tarafı Çözüm Desenleri serisinin "Toplu Import ve Validation Raporu: Excel/CSV Yükle, Staging Tablosu, Satır Bazlı Hata Dosyası" yazısında.
Atomik mi, Kısmi Başarı mı?
Asıl soru, reddedilen satırlar varken ne olacağı. İki seçenek var: hiçbir şey yapmamak (atomik) ya da kabul edilen satırları işleyip reddedilenleri raporlamak (kısmi başarı). Rehberler burada ayrışıyor. AIP-233'e göre senkron bir batch create atomik olmak zorunda; kısmi başarı yalnız asenkron, LRO (long-running operation; uzun süren işlem) dönen method'larda ve hatalı istekleri indeksleriyle listeleyen bir alanla mümkün. Zalando ise kural #152'de toplu isteklerin, bütün item'lar başarısız olsa bile, her item'ın durumunu taşıyan bir 207 Multi-Status ile dönmesini zorunlu tutar.
Bookstore ikisinden de farklı bir yol seçti ve bunu bir ADR (Architecture Decision Record; mimari karar kaydı) olarak ADR-0006'ya yazdı. Toplu sipariş kendi başına bir resource: order-batches koleksiyonuna eklenen, kalıcı bir raporu olan bir kayıt. İstek bu resource'u oluşturduğu için 201 dönüyor ve Location raporun adresini gösteriyor; kabul edilen satırlar tek bir siparişe dönüşüyor. 207 Multi-Status, HTTP'nin değil WebDAV'ın (Web Distributed Authoring and Versioning; HTTP'nin dosya yönetimi uzantısı) RFC'sinden (Request for Comments; internet standartlarının numaralı dokümanları) geliyor ve her item için bir HTTP status code taşıyan XML bir gövde tanımlıyor. Bizim satırlarımız HTTP isteği değil, ve bir 2xx yanıtında rapor okumak her istemci için 207'yi ayrıca ele almaktan daha kolay. Okulun ihtiyacı da kısmi başarı: stokta olmayan bir kitap yüzünden 499 kitabın siparişini durdurmak istemiyorlar. Atomik davranışı isteyen istemci için allOrNothing var:
$ curl -s -H "Authorization: Bearer nevin" http://127.0.0.1:52318/orders/$(tail -1 batch-created.txt | jq -r .orderId) | jq -c '{status, unitId, items: [.items[] | {title, quantity, unitPrice: .unitPrice.amount}], total: .total.amount}'
{"status":"Pending","unitId":"main-campus","items":[{"title":"Nineteen Eighty-Four","quantity":15,"unitPrice":197.10},{"title":"Brave New World","quantity":10,"unitPrice":224.10},{"title":"The Great Gatsby","quantity":12,"unitPrice":179.10},{"title":"The Hobbit","quantity":18,"unitPrice":314.10}],"total":13000.50}
$ jq '.allOrNothing = true' batch.json | curl -s -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-2026-11-strict"' --data @- http://127.0.0.1:52318/institutions/lakeside-school/order-batches | jq -c '{status, type, detail, rejected: [.results[] | select(.status == "Rejected") | .line]}'
{"status":422,"type":"https://api.example.com/problems/batch-rejected","detail":"No order was created: 3 of 7 lines were rejected; see results.","rejected":[3,5,6]}
Kabul edilen dört satır, kurumsal %10 indirimli fiyatla bekleyen bir siparişe dönüştü. allOrNothing ile aynı liste 422 alıyor ve hiçbir sipariş oluşmuyor; problem'in içindeki results yine satır satır nedenleri veriyor. Önce Tahmin Et'teki ilk iki sorunun cevabı burada: 201, "toplu sipariş kaydı oluştu" demek, "her satır sipariş edildi" değil. İstemci her zaman raporu okumalı ve bu, contract'ta yazılı. Raporun satır sonuçları da 04. yazıdaki hata contract'ının aynısı: her reddedilen satır kendi Problem Details nesnesini taşıyor ve problem türleri katalogdakiler. 6. satır, 1. satırla aynı ISBN'i (uluslararası standart kitap numarası) taşıdığı için errors içinde duplicate koduyla reddedildi.
Bulk İstekte Authorization
Bulk endpoint'lerin en tehlikeli hatası, authorization'ı yalnız endpoint seviyesinde yapıp satırların içine bakmamak. "Bu kullanıcı toplu sipariş verebilir" kontrolü geçer, sonra döngü her satırda istemcinin gönderdiği kimliklere sorgusuz işlem yapar. Tek tek isteklerde var olan her kaynak kontrolü (bu sipariş bu kullanıcının mı, bu birim bu alıcının mı) bulk istekte de her item için çalışmalı (BS-73). Bookstore'da birim, bütün toplu sipariş için tek bir alan; satırlar başka bir birim belirtemiyor, kontrol de bir kez yapılıyor:
$ jq '.unitId = "east-campus"' batch.json | curl -s -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-east"' --data @- http://127.0.0.1:52318/institutions/lakeside-school/order-batches | jq -c '{status, type, detail}'
{"status":403,"type":"https://api.example.com/problems/unit-not-allowed","detail":"Buyers can only see and place the orders of their own unit (main-campus)."}
Satırların farklı resource'lara dokunduğu bir bulk endpoint'te (örneğin "şu 40 siparişi iptal et") bu kontrol her satırda yapılmalı ve yetkisiz satır, var olmayan satırla aynı cevabı almalı; aksi hâlde bulk endpoint, başkalarının sipariş kimliklerini tek istekte yoklamanın yolu olur. Bu sınıf açık, yani BOLA (Broken Object Level Authorization; kullanıcının kimliği değiştirerek başkasının kaydına erişebilmesi), API Güvenliği serisinde ayrıntılı anlatılıyor. Bulk endpoint'in kendisi de bir kaynak tüketimi riski: tek bir istek 500 satırlık iş yaptırıyor, bu yüzden boyut sınırı ve aşağıdaki kota birlikte düşünülmeli.
Sonucu Bildirmek: Polling, Webhook ve SSE
Yedi satır milisaniyeler içinde işleniyor, ama her satır depo sisteminde stok ayırma demek ve 500 satırlık bir liste saniyeler sürebilir. Bu yüzden aynı endpoint, RFC 7240'ın tanımladığı Prefer: respond-async header'ıyla 07. yazıdaki uzun süren işleme dönüşebiliyor (BS-74). Server tercihi uyguladığını Preference-Applied ile söylüyor; uygulamasaydı istemci normal bir 201 alırdı ve yine çalışırdı. Tercih bir istek, bir emir değil.
$ curl -s -i -X POST -H "Authorization: Bearer grace" -H "Content-Type: application/json" -H 'Prefer: respond-async' -H 'Idempotency-Key: "city-library-2026-11"' -d '{"unitId":"central","lines":[{"isbn":"9780141439587","quantity":5},{"isbn":"9780553293357","quantity":4}]}' http://127.0.0.1:52318/institutions/city-library/order-batches | tee batch-accepted.txt | grep -E '^(HTTP|Retry-After|RateLimit|Preference-Applied|Operation-Location)'
HTTP/1.1 202 Accepted
Retry-After: 1
RateLimit-Policy: "batches";q=5;w=60
RateLimit: "batches";r=4;t=60
Preference-Applied: respond-async
Operation-Location: /operations/01a1dc64-a8eb-7269-aa36-c709c0007ee3
$ sleep 1; curl -s -H "Authorization: Bearer grace" "http://127.0.0.1:52318$(grep Operation-Location batch-accepted.txt | cut -d' ' -f2 | tr -d '\r')" | jq -c '{status, resourceLocation}'
{"status":"Succeeded","resourceLocation":"/institutions/city-library/order-batches/01a1dc64-a8f1-7255-b9d4-a689fb8b22d9"}
İşin bittiğini öğrenmenin üç yolu var. Polling (istemcinin belirli aralıklarla sorması) en basiti: istemcinin dışarıdan erişilebilir bir adrese ihtiyacı yok, firewall arkasındaki bir okul sistemi bile çalışır; bedeli, boşa giden istekler ve Retry-After kadar gecikme. Webhook'ta server, iş bitince istemcinin önceden kaydettiği bir URL'e kendisi istek atar; gecikme yok, ama istemcinin internete açık, imzayı doğrulayan, tekrar gelen event'i ayıklayan bir endpoint işletmesi gerekir. SSE (Server-Sent Events; server'ın açık bir HTTP bağlantısı üzerinden istemciye event akıttığı standart) ise kullanıcı ekrandayken ilerleme çubuğu göstermek için uygun, ama bağlantı açık kaldıkça çalışır ve bir entegrasyonun gece çalışan job'ı için uygun değildir.
Bookstore şimdilik polling sunuyor ve webhook'u planlıyor. Planlanan event bile contract'ın parçası (BS-76): OpenAPI 3.1'den beri dokümanın üst seviyesindeki webhooks alanı, API'nin dışarıya göndereceği istekleri tanımlıyor. Okulların entegrasyon ekipleri payload'ı şimdiden görebiliyor:
webhooks:
orderBatchCompleted:
post:
operationId: orderBatchCompletedWebhook
summary: A bulk order finished (planned)
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [id, type, occurredAt, data]
properties:
id:
type: string
description: Unique event id; receivers use it to drop duplicates.
type:
type: string
const: order-batch.completed
occurredAt:
type: string
format: date-time
data:
type: object
required: [batchId, institutionId, acceptedLines, rejectedLines, links]
Event'te raporun tamamı değil, raporun adresi var. Webhook'lar en az bir kez teslim edilir, sıraları garanti değildir ve bir saldırgan sahte bir event gönderebilir; ince bir event'i alan istemci asıl veriyi API'den, kendi kimliğiyle okur. Webhook'u imzalamak, outbox ile teslim etmek, tekrar denemek ve alan tarafta doğrulamak External Service Integration ve Resilience serisinin "Webhook Göndermek: Standard Webhooks, İmzalama, Outbox ile Teslimat ve Retry Takvimi" ve "Webhook Almak: İmza Doğrulama, Replay Koruması, Hızlı 2xx ve Idempotent İşleme" yazılarında. Event'lerin bir message broker üzerinden yayımlandığı durumda contract'ın AsyncAPI ile yazılması ise Messaging ve Event-Driven Architecture serisinin "Message Contract'ları ve Schema Evolution: CloudEvents, AsyncAPI ve Versioning" yazısında.
Rate Limit'i Contract Olarak Yazmak
Toplu sipariş pahalı bir işlem, bu yüzden bir kotası var: kurum başına dakikada beş toplu sipariş (BS-75). Kotanın asıl amacı istemciyi cezalandırmak değil, istemcinin kendi hızını ayarlayabilmesi için kuralı görünür yapmak. Bunun için IETF'in (internet standartlarını geliştiren kuruluş) HTTP API'leri çalışma grubunun RateLimit header'ları taslağını kullanıyoruz:
$ for i in 1 2 3; do curl -s -D - -o /dev/null -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H "Idempotency-Key: \"lakeside-retry-$i\"" --data @batch.json http://127.0.0.1:52318/institutions/lakeside-school/order-batches | grep -E '^(HTTP|RateLimit|Retry-After)'; done
HTTP/1.1 201 Created
RateLimit-Policy: "batches";q=5;w=60
RateLimit: "batches";r=1;t=60
HTTP/1.1 201 Created
RateLimit-Policy: "batches";q=5;w=60
RateLimit: "batches";r=0;t=60
HTTP/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Policy: "batches";q=5;w=60
RateLimit: "batches";r=0;t=60
$ curl -s -X POST -H "Authorization: Bearer nevin" -H "Content-Type: application/json" -H 'Idempotency-Key: "lakeside-retry-4"' --data @batch.json http://127.0.0.1:52318/institutions/lakeside-school/order-batches | jq .
{
"type": "https://api.example.com/problems/quota-exceeded",
"title": "Quota exceeded",
"status": 429,
"detail": "Policy batches allows 5 requests per 60 seconds; wait for Retry-After seconds.",
"instance": "/institutions/lakeside-school/order-batches",
"violatedPolicies": [
"batches"
],
"traceId": "00-de552911bb54186dd8c3ec54d3eb5264-cea4749ab41137de-00"
}
Taslak iki header tanımlıyor. RateLimit-Policy kuralın kendisi: "batches";q=5;w=60, "batches" adlı politikada 60 saniyede 5 birimlik kota demek; her yanıtta aynı kalması beklenir. RateLimit o anki durum: r kalan kota, t bu kotanın geçerli olduğu saniye. Değerler Structured Field biçiminde; politika adı tırnak içinde bir string. Kota bitince 429 Too Many Requests (RFC 6585) ve Retry-After geliyor; taslağa göre ikisi birlikte varsa Retry-After önceliklidir ve pencerenin bitişinden önceki bir anı göstermemelidir. 400 alan şema hataları ve sınırı aşan istekler kotadan düşmüyor, 403 ve 422 düşüyor; taslak hangi yanıtların kotayı tükettiğini server'a bırakır, biz de bunu contract'a yazdık. Problem türü kendi kataloğumuzda; taslak IANA (Internet Assigned Numbers Authority; internet protokollerinin ortak kayıtlarını tutan kurum) kaydında bir quota-exceeded türü ve violated-policies alanı öneriyor, ama taslak RFC olmadığı için bu kayıt henüz yok. Biz alanı kendi isimlendirme kuralımızla violatedPolicies olarak döndük.
Taslağın durumunu bu yazının yazıldığı gün (15 Kasım 2026) datatracker'dan kontrol ettik: draft-ietf-httpapi-ratelimit-headers-11, 23 Mayıs 2026 tarihli, "Active Internet-Draft", çalışma grubu dokümanı; süresi 24 Kasım 2026'da doluyor ve -12 henüz yayımlanmadı. Yani bu header'lar bir standart değil ve biçimi değişebilir. Zalando'nun kural #153'ü bugün hâlâ X-RateLimit-Limit, X-RateLimit-Remaining ve X-RateLimit-Reset üçlüsüne izin verir; GitHub gibi büyük API'ler de bu eski adları kullanıyor. Biz taslağı seçtik ve "taslak değişirse header biçimini yeniden değerlendir" maddesini ADR-0006'ya yazdık. Önemli olan header'ların adı değil, kotanın dokümante edilmiş ve istemcinin okuyabildiği bir kural olması. Kaynak tüketiminin diğer boyutları (sayfa boyutu, sorgu karmaşıklığı, zaman aşımları) API Güvenliği serisinin kaynak tüketimi yazısında.
ASP.NET Core'da
ASP.NET Core 7'den beri hazır bir rate limiting middleware var (AddRateLimiter, RequireRateLimiting), ama iki varsayılanına dikkat etmek gerekiyor: reddedilen isteğe 503 döner (429 için RejectionStatusCode'u ayarlamak gerekir) ve Retry-After'ı kendisi yazmaz; OnRejected içinde lease'in MetadataName.RetryAfter değerini okuyup yazmak gerekir. Başarılı yanıtlarda kalan kotayı da göstermediği için Bookstore'da kotayı küçük bir endpoint filter olarak yazdık: kurum başına sabit pencereli bir sayaç, her yanıta iki header, kota bitince Problem Details. Hem middleware'in hem bu filter'ın sayaçları bellekte; iki instance çalışan bir uygulamada kota fiilen ikiye katlanır, bu yüzden ortak bir store ya da gateway'de uygulanan bir limit gerekir. Toplu siparişte OrderBatchRequest ve satırları .NET 10'un AddValidation'ıyla doğrulanıyor; iç içe koleksiyonlar için ürettiği Lines[1].Quantity anahtarı, 04. yazıdaki normalizasyonla lines[1].quantity'ye çevriliyor. Rate limiting middleware'in kendisi ASP.NET Core Web API serisinin ".NET 7 ile ASP.NET Core Yenilikleri: MapGroup, TypedResults, Rate Limiting ve Output Caching" yazısında anlatılıyor.
Sık Düşülen Tuzaklar
Bulk endpoint'i authorization'sız bir döngüye çevirmek. Endpoint'e erişim kontrolü, satırların dokunduğu her resource için ayrıca kontrol yapma ihtiyacını ortadan kaldırmaz.
Sınırsız bulk. 500 satırın üstü için bir sınır yazılmamışsa, ilk büyük müşteri 50.000 satırlık bir istekle zaman aşımına düşer ve bir sonraki deneme aynı işi tekrar başlatır.
201'i "hepsi tamam" diye okumak. Kısmi başarı contract'ında başarılı status code yalnız işlemin kaydedildiğini söyler; rapor okunmazsa reddedilen satırlar sessizce kaybolur.
Bulk isteği Idempotency-Key'siz bırakmak. Zaman aşımına uğrayan 500 satırlık bir istek tekrar gönderildiğinde iki sipariş oluşur. Bookstore'da toplu sipariş de 07. yazıdaki anahtarı istiyor.
Kotayı yalnız 429 ile duyurmak. İstemci kuralı ancak duvara çarpınca öğreniyorsa hızını ayarlayamaz; kalan kotayı her yanıtta göstermek ve dokümana yazmak daha az 429 demek.
Küçük Bir Deneme
★☆☆ 50 satırlık bir liste üret ve Prefer: respond-async ile gönder. Monitor'ü Retry-After'a uyarak sorgula; percentComplete nasıl ilerliyor?
★★☆ Satırları Excel'den gelen bir okul için raporu CSV (virgülle ayrılmış değerler) olarak da sunmak istiyoruz. Bunu ayrı bir endpoint ile mi, Accept: text/csv ile content negotiation olarak mı tasarlardın? Hata satırlarının Problem Details'ını CSV'de nasıl gösterirsin?
★★★ "Kurum başına dakikada 5" kotasının yanına "kurum başına günde 10.000 satır" kotasını ekle. İki politikayı RateLimit-Policy'de nasıl gösterirsin, bir istek hangisini ihlal ettiğini nereden anlar? Kotası satır sayısıyla ölçülen bir politika için taslaktaki qu parametresine bak.
Bu yazıyla serinin ikinci bloğu bitti: contract'ın zamanla değişimi, eşzamanlı ve tekrarlanan istekler, uzun süren işler ve toplu işlemler. Son blok contract'ı yönetmekle ilgili. Bir sonraki yazıda şimdiye kadar elle büyüttüğümüz OpenAPI dokümanını design-first akışın merkezine koyuyor, style guide'ı Spectral kurallarına çeviriyor, breaking change'leri PR'da (pull request; değişikliği ana branch'e almak için açılan istek) otomatik yakalıyor ve contract'tan mock server ile Angular client üretiyoruz.