API-First ve OpenAPI 3.2 ile Contract: Design-First Akış, Spectral ile Lint, Breaking Change Diff ve Mock Server
Design-first akışta OpenAPI contract'ı bir build girdisidir: her PR'da style guide lint edilir, hedef branch'e göre breaking change aranır, üretilen client'ın güncelliği ve koddan üretilen dokümanla drift kontrol edilir. Bookstore'da bir Spectral kuralının neden hiç hata vermediğini, oasdiff'in silinen parametreyi neden yalnız uyarı saydığını, eski RPC endpoint'ini bulan drift kontrolünü, Prism mock'unu ve openapi-typescript ile Angular tiplerini gerçek çıktılarla görüyoruz.
Sürüm notu: Bu yazıdaki kodlar C# 14 ve .NET 10 (ASP.NET Core 10.0.15) ile, Angular örneği Angular 22.2 ve TypeScript 6.0 ile derlenip denenmiştir; HTTP örnekleri bu uygulamanın gerçek yanıtlarıdır. Araçlar: Redocly CLI 2.78.0, Spectral 6.17.1, oasdiff 1.37.0, Prism 5.16.0, openapi-typescript 7.13.0.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore'un (bir online kitapçı) API'sinde Emre bir PR (pull request; değişikliği ana branch'e almak için açılan istek) açıyor. İki değişiklik var: fiyat filtrelerinin adlarını daha okunur bulduğu priceFrom/priceTo yapıyor ve vergi numarası değişen kurumlar için faturayı yeniden üreten bir endpoint ekliyor. Contract'taki değişiklik:
$ git diff contract/bookstore.openapi.yaml
diff --git a/contract/bookstore.openapi.yaml b/contract/bookstore.openapi.yaml
index 7a516b2..8f72d7e 100644
--- a/contract/bookstore.openapi.yaml
+++ b/contract/bookstore.openapi.yaml
@@ -53,11 +53,11 @@ paths:
description: Exact name of one of the authors, case-insensitive.
schema:
type: string
- - name: minPrice
+ - name: priceFrom
in: query
schema:
type: number
- - name: maxPrice
+ - name: priceTo
in: query
schema:
type: number
@@ -567,6 +567,30 @@ paths:
$ref: '#/components/responses/Problem'
'404':
$ref: '#/components/responses/Problem'
+ /orders/{orderId}/invoices/{invoiceId}:regenerate:
+ parameters:
+ - $ref: '#/components/parameters/ApiVersion'
+ - $ref: '#/components/parameters/OrderId'
+ - name: invoiceId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ post:
+ operationId: regenerateInvoice
+ summary: Regenerate an invoice
+ description: Builds the PDF again, for example after the tax number changed.
+ tags: [Orders]
+ responses:
+ '202':
+ description: Accepted; the invoice is being regenerated.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Operation'
+ '404':
+ $ref: '#/components/responses/Problem'
/operations/{operationId}:
parameters:
- $ref: '#/components/parameters/ApiVersion'
Contract'ta iki sorun var. Parametre adlarını değiştirmek, minPrice gönderen her istemciyi 400'e düşürür, çünkü 05. yazıdan beri bilinmeyen parametre hata alıyor. Yeni endpoint de 07. yazıdaki kuralı çiğniyor: 202 dönüyor ama Operation-Location ve Retry-After yok. Soru: Bu PR'ın review'a gelmeden durması için hangi araç hangi sorunu yakalamalı? Tahminini yap; ilk denemede ikisi de yakalanmadı.
Code-First mi, Design-First mi?
Code-first akışta önce endpoint yazılır, OpenAPI dokümanı koddan üretilir. Hızlıdır ve doküman her zaman kodla aynıdır, ama tasarım kararları kodun yan ürünü olur: tüketici contract'ı endpoint bittikten sonra görür ve itiraz ettiğinde iş yeniden yapılır. Design-first akışta önce contract yazılır ve review edilir; kod contract'ı takip eder. Bu serinin ilk yazısından beri yaptığımız buydu, ama bir eksikle: contract'ın kurallara uyduğunu lint kontrol ediyordu, contract'ın değişiminin tüketiciyi kırıp kırmadığını ve kodun contract'a uyup uymadığını ise kimse kontrol etmiyordu. Bu yazıda bu iki boşluğu kapatıyor ve kararı bir ADR (Architecture Decision Record; mimari karar kaydı) olarak, ADR-0007'ye yazıyoruz.
Design-first'ün bedeli disiplin: contract'ı kodla senkron tutmak bir araç zinciri ister. Getirisi ise erken geri bildirim. Okulların entegrasyon ekipleri, endpoint daha yazılmadan contract'tan bir mock server ve client tipleri alıp kendi işlerine başlayabiliyor. Integration ve E2E (end-to-end; uçtan uca) Test serisi aynı problemi Angular tarafından ele alıyor: "Angular ile API Arasındaki Contract: OpenAPI Dokümanı, Breaking Change Tespiti ve Ne Zaman Pact?" yazısında istemcinin contract'a bağımlılığı test açısından anlatılıyor; burada contract'ın sahibi olan API ekibinin tarafındayız.
OpenAPI 3.2 ve Araçların Durumu
Contract'ımız ilk yazıdan beri OpenAPI 3.2.0 ile yazılıyor. 3.2.0, 19 Eylül 2025'te yayımlandı; 10 Eylül 2026'da çıkan 3.2.1 bir düzeltme sürümü. Spec'te 3.1'e göre bizim için önemli olan eklemeler: Path Item'da query operation'ı, yani RFC'lerden (Request for Comments; internet standartlarının numaralı dokümanları) 10008 numaralısının tanımladığı QUERY (kriterleri body'de taşıyan, GET gibi safe bir HTTP method'u) için bir alan ve standart dışı method'lar için additionalOperations, bütün query string'i tek bir değer olarak tanımlayan in: querystring parametresi, satır satır gelen içerik (JSON Lines, Server-Sent Events) için media type'ta itemSchema, tag'ler için parent ve kind, dokümanın kendi adresini veren $self, security scheme'lerde deprecated, oauth2MetadataUrl ve OAuth device authorization flow. Spec hazır; araçlar ise farklı hızlarda geliyor. Bu seride kullandığımız araçlarla bugün gördüklerimiz:
| Araç | Sürüm | OpenAPI 3.2 ile durumu |
|---|---|---|
| Redocly CLI | 2.78.0 | 3.2'yi doğruluyor, query operation'ını tanıyor |
| Spectral | 6.17.1 | 3.2 dokümanında şema doğrulamasını atlıyor, query operation'ını kurallara dahil etmiyor |
| oasdiff | 1.37.0 | 3.2 dokümanlarını karşılaştırıyor, QUERY /books'u da görüyor |
| Prism | 5.16.0 | Dokümanı mock'luyor, QUERY isteğine 405 dönüyor |
| openapi-typescript | 7.13.0 | İçindeki doğrulayıcı query'yi hata sayıyor; kapatınca tipleri üretiyor ama QUERY için tip yok |
| ASP.NET Core | 10.0.15 | Koddan OpenAPI 3.1.1 üretiyor; QUERY endpoint'i dokümanda yok |
Bu tablo bir karar sonucu doğuruyor: contract'ı 3.2 ile yazmak, araçların bir kısmının yeni alanları görmezden gelmesini kabul etmek demek. Bizim için tek etkilenen yer QUERY ve bunu ADR-0007'ye açıkça yazdık. 3.1 ile yazmak da bir seçenekti, ama o zaman QUERY'yi contract'ta hiç anlatamazdık.
Style Guide'ı Lint Kuralına Çevirmek
Style guide'daki [lint] etiketli kurallar .spectral.yaml'da birer kural. 07. yazıdaki BS-63 için, yani "her 202, status monitor'ünü göstermeli" kuralı için ilk yazdığımız Spectral kuralı şuydu:
bookstore-lro-headers:
description: A 202 response points to its status monitor (BS-63).
message: "{{path}} needs Operation-Location and Retry-After"
severity: error
given: $.paths[*][*].responses['202'].headers
then:
- field: Operation-Location
function: truthy
- field: Retry-After
function: truthy
Kural mevcut contract'ta hata vermedi ve doğru çalıştığını varsaydık. Emre'nin PR'ında da hata vermedi. Sebep given'da: kural 202'nin headers nesnesini seçiyor, Emre'nin 202'sinde ise headers hiç yok. Seçilecek bir şey olmayınca Spectral kontrol edecek bir şey de bulmuyor. Kuralın hedefini 202'nin kendisi yapınca PR yakalanıyor:
# 202'nin header'larını değil kendisini seç: header'sız bir 202 de hata vermeli.
given: $.paths[*][*].responses['202']
then:
- field: headers.Operation-Location
function: truthy
- field: headers.Retry-After
function: truthy
$ npx spectral lint contract/bookstore.openapi.yaml
/home/user/bookstore/contract/bookstore.openapi.yaml
586:15 error bookstore-lro-headers #/paths/~1orders~1%7BorderId%7D~1invoices~1%7BinvoiceId%7D%3Aregenerate/post/responses/202 needs Operation-Location and Retry-After paths./orders/{orderId}/invoices/{invoiceId}:regenerate.post.responses[202]
✖ 1 problem (1 error, 0 warnings, 0 infos, 0 hints)
Ders şu: bir lint kuralı da kod gibi test edilmeli. Kuralı yazınca, kuralı çiğneyen küçük bir örnek dokümanla bir kez çalıştırıp hata verdiğini görmeden ona güvenme. Bu yazıda bir kural daha ekledik: deprecated: true işaretli her operation ve property bir description taşımalı, yani neyin yerine geçtiğini ve ne zaman kalkacağını söylemeli (BS-54). Kararları otomatik kontrollere çevirmenin genel yaklaşımı Architecture Decision'lar serisinin "ADR'dan Otomatik Kontrole: Kararları Fitness Function ve CI ile Doğrulamak" yazısında.
Breaking Change'i PR'da Yakalamak
Lint tek bir dokümana bakar; breaking change ise iki doküman arasındaki farktır. oasdiff, iki OpenAPI dokümanını karşılaştırıp değişiklikleri kurallarına göre sınıflandırıyor. Önce aracı geçmişe karşı denedik: 05. yazının contract'ı ile bugünkü contract arasında ne kırıldı?
$ git show rest-api-tasarimi/05:contract/bookstore.openapi.yaml > v05.yaml
$ oasdiff breaking v05.yaml contract/bookstore.openapi.yaml | head -1
9 changes: 9 error, 0 warning, 0 info
$ oasdiff breaking v05.yaml contract/bookstore.openapi.yaml --format singleline | grep -o -E '\[[a-z-]+\]' | sort | uniq -c
2 [request-parameter-became-required]
7 [response-property-became-optional]
Dokuzu da bildiğimiz değişiklikler: author'ın zorunlu alanlardan çıkması (06. yazı, yedi response'ta) ve If-Match'in PATCH ile DELETE'te zorunlu olması (07. yazı). İkisini de bilerek yaptık ve gerekçelerini ADR'lara yazdık. Araç gerekçeyi bilmiyor; görevi değişikliği görünür yapmak, kararı vermek ise review'un işi. Bookstore'un kuralı da bu (BS-82): oasdiff'in raporladığı bir breaking change ancak yeni bir api-version ya da hiçbir tüketicinin kırılmadığını anlatan bir ADR ile kabul edilir. Şimdi Emre'nin PR'ı:
$ git show main:contract/bookstore.openapi.yaml > base.yaml
$ oasdiff breaking base.yaml contract/bookstore.openapi.yaml --fail-on ERR; echo "exit code: $?"
2 changes: 0 error, 2 warning, 0 info
warning [request-parameter-removed] at contract/bookstore.openapi.yaml
in API GET /books
deleted the `query` request parameter `maxPrice`
This is a warning because some clients may return an error when receiving an unexpected parameter. It is recommended to deprecate the parameter first.
warning [request-parameter-removed] at contract/bookstore.openapi.yaml
in API GET /books
deleted the `query` request parameter `minPrice`
This is a warning because some clients may return an error when receiving an unexpected parameter. It is recommended to deprecate the parameter first.
exit code: 0
oasdiff silinen parametreyi görüyor, ama bir uyarı olarak; --fail-on ERR ile build geçiyor. Aracın varsayımı, server'ın bilmediği bir parametreyi yok sayacağı. Bookstore'da bu varsayım doğru değil: 05. yazıdan beri bilinmeyen parametre 400 alıyor, yani minPrice gönderen her istemci yarın hata alacak. Aracın şiddet seviyeleri genel bir API'ye göre ayarlı; senin contract'ının kuralları farklıysa eşiği ona göre seçmen gerekiyor. CI'da eşiği --fail-on WARN yaptık:
$ oasdiff breaking base.yaml contract/bookstore.openapi.yaml --fail-on WARN --format singleline; echo "exit code: $?"
2 changes: 0 error, 2 warning, 0 info
warning at contract/bookstore.openapi.yaml, in API GET /books deleted the `query` request parameter `maxPrice` [request-parameter-removed]. This is a warning because some clients may return an error when receiving an unexpected parameter. It is recommended to deprecate the parameter first.
warning at contract/bookstore.openapi.yaml, in API GET /books deleted the `query` request parameter `minPrice` [request-parameter-removed]. This is a warning because some clients may return an error when receiving an unexpected parameter. It is recommended to deprecate the parameter first.
exit code: 1
oasdiff'in önerisi de doğru yol: yeni adları ekle, eskilerini deprecated yap, kullanım bitince 06. yazıdaki gibi kaldır. Önce Tahmin Et'in cevabı da bu iki bölümde: style kuralı ihlalini Spectral (kuralı düzelttikten sonra), breaking change'i oasdiff (eşiği düzelttikten sonra) yakaladı. İkisi de ilk hâliyle PR'ı geçirmişti.
Kod ile Contract Arasındaki Drift
Design-first'ün bilinen zayıf noktası, kodun contract'tan sessizce uzaklaşması: biri contract'ta olmayan bir endpoint ekler ya da contract'taki bir endpoint hiç yazılmaz. ASP.NET Core 10, koddan bir OpenAPI dokümanı üretebiliyor. Bu doküman yayımladığımız contract değil, ama kodun gerçekte neyi sunduğunun güvenilir bir listesi. Küçük bir Node.js script'i iki dokümandaki operation'ları karşılaştırıyor. İlk çalıştırmanın çıktısı:
$ npm run -s drift
bundling contract/bookstore.openapi.yaml...
📦 Created a bundle for contract/bookstore.openapi.yaml at contract/.bundled.json 9ms.
only in code: POST /legacy/rpc
allowed: QUERY /books (ASP.NET Core 10 generates OpenAPI 3.1.1, which has no query operation)
27 operations in the contract, 27 in the code, 1 drifting
İlk yazıdan beri kodda duran eski RPC (Remote Procedure Call; uzaktaki bir fonksiyonu çağırır gibi tasarlanmış API) endpoint'i contract'ta hiç yoktu. 06. yazıda ona Deprecation ve Sunset header'larını ekledik, ama contract'a bakan biri onun varlığından haberdar değildi. Dokümante edilmemiş, unutulmuş endpoint'ler (shadow API) güvenlik açısından da risk; API envanterini OpenAPI ile tutmak API Güvenliği serisinin yanlış yapılandırma ve envanter yazısında anlatılıyor. Çözüm endpoint'i contract'a deprecated: true ile eklemekti; yeni lint kuralı da ondan bir açıklama istedi. QUERY ise bilinen bir fark: üretilen doküman 3.1.1 ve QUERY'yi anlatamıyor, bu yüzden script'te gerekçesiyle izinli.
$ curl -s http://127.0.0.1:52318/openapi/v1.json | jq -r .openapi
3.1.1
$ npm run -s drift
allowed: QUERY /books (ASP.NET Core 10 generates OpenAPI 3.1.1, which has no query operation)
28 operations in the contract, 27 in the code, 0 drifting
Contract'tan Mock Server ve Client
Contract'ın en somut getirisi, kod yazılmadan kullanılabilmesi. Prism, OpenAPI dokümanını okuyup her operation için contract'taki örnekleri ya da şemadan üretilmiş değerleri dönen bir mock server ayağa kaldırıyor (npm run mock). Prefer: code=404 header'ıyla istenen status code'u seçmek de mümkün. İlk denemede bu isteğe 404 status'lu ama gövdesinde 422'lik stok hatası olan bir yanıt geldi: bütün hata response'ları tek bir ortak Problem response'unu kullanıyordu ve Prism o response'taki ilk örneği, yani stok hatasını seçiyordu. Mock, contract'taki örneklerin söylediğini söyler. Ortak response'tan örnekleri çıkarıp NotFound ve ValidationFailed adında, kendi örnekleri olan response'lar tanımladık:
$ curl -s -i "http://127.0.0.1:52328/books/9780441172719?api-version=2026-11-15" | grep -E '^(HTTP|Content-type)|^\{'
HTTP/1.1 200 OK
Content-type: application/json
{"isbn":"9780441172719","title":"Dune","authors":["Frank Herbert"],"category":"science-fiction","price":{"amount":489,"currency":"TRY"},"inStock":true}
$ curl -s -i -H "Prefer: code=404" "http://127.0.0.1:52328/books/9780441172719" | grep -E '^HTTP|^\{'
HTTP/1.1 404 Not Found
{"type":"https://api.example.com/problems/not-found","title":"Not found","status":404,"detail":"Nothing exists at /books/9780000000002.","instance":"/books/9780000000002","traceId":"00-6f1c2a9e0b4d4e8f9a7c3b2d1e0f4a5b-1a2b3c4d5e6f7a8b-00"}
$ curl -s -X QUERY -H "Content-Type: application/json" -d '{"isbns":["9780441172719"]}' http://127.0.0.1:52328/books | jq -c '{status, title}'
{"status":405,"title":"Route resolved, but no method matched"}
Mock bir test sunucusu değil: iş kuralı yok, stok düşmüyor, 404'ün gövdesindeki ISBN (uluslararası standart kitap numarası) istekteki ISBN değil. Amacı istemci ekibinin şekli ve hata yollarını erkenden görmesi. Postman'in mock server'ı API Araçları serisinin "Postman Derinlemesine: Collection, Environment, Variable Scope'ları, Script'ler, Test'ler, Mock Server ve CLI" yazısında anlatılıyor.
Angular tarafında openapi-typescript, contract'tan yalnız TypeScript tipleri üretiyor; HTTP çağrısını Angular'ın HttpClient'ı yapıyor. Böylece ne bir runtime library'si ne de üretilmiş bir service sınıfı bundle'a giriyor. Üretilen Book tipinde author, @deprecated JSDoc etiketiyle işaretli ve editörde üstü çizili görünüyor; OrderStatus ise contract'ta açık bir liste olduğu için string. 06. yazıdaki tolerant reader kuralı tipe de yansımış oldu. Catalog service'i:
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import type { components, operations } from './api/bookstore';
// Tipler contract/bookstore.openapi.yaml'dan üretiliyor (npm run generate:client); elle değiştirilmez.
export type Book = components['schemas']['Book'];
export type BookList = components['schemas']['BookList'];
export type ListBooksQuery = Omit<NonNullable<operations['listBooks']['parameters']['query']>, 'api-version'>;
@Injectable({ providedIn: 'root' })
export class CatalogService {
private readonly http = inject(HttpClient);
// Parametre adları ve tipleri contract'tan geliyor: yanlış yazılmış bir filtre derlenmez.
listBooks(query: ListBooksQuery = {}): Observable<BookList> {
let params = new HttpParams().set('api-version', '2026-11-15');
for (const [name, value] of Object.entries(query)) {
if (value !== undefined) {
params = params.set(name, String(value));
}
}
return this.http.get<BookList>('/books', { params });
}
}
$ npx tsc -p tsconfig.json --noEmit
src/catalog.usage.ts(5,45): error TS2561: Object literal may only specify known properties, but 'catgory' does not exist in type 'ListBooksQuery'. Did you mean to write 'category'?
05. yazıdaki catgory yazım hatası, API'ye hiç ulaşmadan derleyicide yakalanıyor. İki not: openapi-typescript 7.13 içinde OpenAPI 3.2'yi tanımayan bir doğrulayıcıyla geliyor ve query operation'ını hata sayıyor; bu kontrolü bir config dosyasıyla kapattık, contract'ın asıl doğrulamasını zaten Redocly CLI yapıyor. Aracın TypeScript peer dependency'si de 5.x; Angular projesi TypeScript 6.0 kullandığı için üretici, contract araçlarıyla birlikte repo'nun kök dizininde kurulu ve Angular projesine yalnız ürettiği .ts dosyası giriyor.
CI'da Hepsi Bir Arada
Dört kontrol her PR'da çalışıyor: lint, hedef branch'e göre breaking change, üretilen client'ın güncelliği ve drift. GitHub Actions workflow'u:
# Contract'a ya da API'ye dokunan her pull request'te çalışır (style guide BS-xx, ADR-0007).
name: contract
on:
pull_request:
paths: ["contract/**", "src/**", ".spectral.yaml", "redocly.yaml", "package*.json"]
jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 24
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
- run: npm ci
# 1. Style guide kuralları (Redocly recommended + Spectral BS-xx kuralları).
- run: npm run lint:contract
# 2. Hedef branch'e göre breaking change'ler. WARN da build'i durdurur: burada bilinmeyen
# query parametresi 400 alır (BS-35), yani silinen parametre istemciyi kırar.
- name: Breaking changes
run: |
curl -fsSL https://github.com/oasdiff/oasdiff/releases/download/v1.37.0/oasdiff_1.37.0_linux_amd64.tar.gz | tar -xz oasdiff
git show "origin/${{ github.base_ref }}:contract/bookstore.openapi.yaml" > base.yaml
./oasdiff breaking base.yaml contract/bookstore.openapi.yaml --fail-on WARN --format githubactions
# 3. Üretilen client contract'la güncel olmalı.
- run: npm run generate:client && git diff --exit-code clients/angular-snippets/src/api
# 4. Kod ve contract aynı operation'ları tanımlamalı.
- name: Drift between code and contract
run: |
dotnet run --project src/Bookstore.Api --urls http://127.0.0.1:52318 &
for i in $(seq 1 60); do curl -fs http://127.0.0.1:52318/openapi/v1.json > /dev/null && break; sleep 1; done
npm run drift
Workflow'u actionlint ile doğruladık; adımları tek tek yerelde çalıştırdık. --format githubactions, oasdiff bulgularını PR'da ilgili satırın yanına not olarak düşürüyor. Üretilen client'ın güncelliği git diff --exit-code ile kontrol ediliyor: biri contract'ı değiştirip client'ı yeniden üretmeyi unutursa build kırılıyor.
ASP.NET Core'da
Üretilen doküman için Microsoft.AspNetCore.OpenApi paketi (10.0.15), AddOpenApi() ve yalnız Development ortamında açılan MapOpenApi() yetiyor; doküman /openapi/v1.json'da. Bu doküman bizim için bir test çıktısı: içinde contract'taki açıklamalar, örnekler ve hata response'ları yok, ama hangi path'te hangi method'un gerçekten var olduğunu kesin biliyor. Endpoint'lere WithSummary, Produces ve ProducesProblem ile metadata eklemek, Scalar ile dokümanı göstermek ve .NET 11'de OpenAPI 3.2 desteği ASP.NET Core Web API serisinin ".NET 9 Yenilikleri: ASP.NET Core'da Yerleşik OpenAPI, Scalar ve HybridCache", ".NET 10 Yenilikleri: ASP.NET Core'da AddValidation, OpenAPI 3.1 ve Server-Sent Events" ve ".NET 11 Yenilikleri: ASP.NET Core'da Async Validation, OpenAPI 3.2 ve C# 15 Union Types" yazılarında.
Sık Düşülen Tuzaklar
OpenAPI'yi yalnız dokümantasyon sanmak. Doküman yalnız insanlara gösteriliyorsa koddan uzaklaşır ve kimse fark etmez. Contract; lint, diff, mock, client ve drift kontrolüyle bir build girdisi olduğunda yaşar.
Üretilen client'ı elle değiştirmek. Elle yapılan düzeltme bir sonraki üretimde kaybolur ya da üretimi durdurur. Yanlış olan contract'sa contract düzeltilir; aracın eksiği varsa üretici ayarlanır.
Lint kuralını test etmeden güvenmek. Seçicisi hiçbir şeye uymayan bir kural hiç hata vermez ve bu, kuralın geçtiği anlamına gelmez.
Araçların varsayılan şiddetini sorgulamamak. oasdiff'in "uyarı" dediği bir değişiklik, senin contract kuralların altında bir breaking change olabilir.
Ortak örnekler. Bütün hata response'larının tek bir örnek setini paylaşması, mock'ta ve dokümanda yanlış status code ile yanlış gövdeyi yan yana gösterir.
Küçük Bir Deneme
★☆☆ bookstore-deprecated-explained kuralının çalıştığını, kuralı çiğneyen küçük bir OpenAPI dokümanıyla göster. Kural hem operation'larda hem property'lerde hata veriyor mu?
★★☆ Emre'nin PR'ını kırmayacak şekilde yeniden yaz: priceFrom/priceTo eklensin, minPrice/maxPrice deprecated olsun. oasdiff ne diyor? İki parametre birlikte gelirse API ne yapmalı?
★★★ Drift script'i yalnız operation'ları karşılaştırıyor. Üretilen dokümandaki response status code'larını da karşılaştıracak şekilde genişlet. Hangi farklar gerçek bir drift, hangileri yalnız ASP.NET Core'un metadata eksikliği?
Son yazıda bu araçların bir ekipte nasıl kullanılacağına geçiyoruz: bir API review checklist'i, kararların ADR'larla tutulması, API envanteri ve Bookstore'un kurumsal partner API'sinin uçtan uca tasarımı.