Bölüm 7 / 11
OpenAPI / Swagger
Dokümantasyon, istemci kodu üretimi.
11 dakikalık okuma
Önceki altı derste bir API sözleşmesi kurduk: kaynaklar, durum kodları, hata gövdesi, sürüm politikası. Ama bu sözleşme şu an yalnız senin kafanda ve kodun içinde. Karşı taraftaki geliştirici onu nasıl öğrenecek? OpenAPI bu soruyu cevaplar: API'nin makine okunur tanımı. Değeri güzel bir belge sayfası üretmek değil — o tanımdan istemci kodu, sahte sunucu, test ve ağ geçidi ayarı üretilebilmesi ve sözleşmenin sessizce değişmesinin yakalanabilmesidir.
01Ne öğreneceksin
- OpenAPI ile Swagger arasındaki fark
- Belgenin yapısı:
paths,components,security - .NET'te belge üretimi ve şemanın koddan nasıl çıkarıldığı
ProblemDetailsve sürümlü dokümanı belgeye yansıtmak- Kod-önce ile sözleşme-önce arasındaki gerçek fark
- Belgeden istemci kodu, sahte sunucu ve koleksiyon üretmek
- Belgeyi üretimde açık bırakmanın güvenlik sonuçları
- Kırıcı değişikliği CI'da yakalamak
02OpenAPI nedir, Swagger nedir
Karışan iki ad: OpenAPI spesifikasyonun kendisidir — bir HTTP API'sini JSON ya da YAML olarak tanımlayan standart. Swagger ise bu standardın eski adı ve bugün onun etrafındaki araç ailesinin markasıdır (Swagger UI, Swagger Editor, Swagger Codegen). Yani "Swagger dokümanı" denen şey aslında bir OpenAPI belgesidir; "Swagger açtım" denen şey genelde Swagger UI sayfasıdır.
Belgenin iskeleti şudur:
openapi: 3.1.0
info:
title: Sipariş Servisi
version: "2.0"
servers:
- url: https://siparis.ornek.local/api/v2
paths:
/siparisler/{no}:
get:
operationId: siparisGetir
summary: Siparişi getirir
parameters:
- name: no
in: path
required: true
schema: { type: integer, format: int32 }
responses:
"200":
description: Sipariş bulundu
content:
application/json:
schema: { $ref: "#/components/schemas/SiparisDto" }
"404":
description: Sipariş yok
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ProblemDetails" }
components:
schemas:
SiparisDto:
type: object
required: [no, urun, adet]
properties:
no: { type: integer }
urun: { type: string, maxLength: 120 }
adet: { type: integer, minimum: 1, maximum: 1000 }
securitySchemes:
bearer: { type: http, scheme: bearer, bearerFormat: JWT }
security:
- bearer: []
Dikkat edilecek üç yapı: paths uç noktaları ve her birinin
metotlarını, parametrelerini ve olası tüm yanıtlarını tanımlar;
components tekrar kullanılan şemaları ve güvenlik tanımlarını tutar
($ref ile atıfta bulunulur); operationId ise kod
üreticilerinin metot adını buradan aldığı, benzersiz olması gereken alandır — üretilen
istemci SDK'sının okunabilirliği doğrudan buna bağlıdır.
Belgenin asıl gücü, bir kez var olduğunda ne üretilebildiğidir:
| Üretilen | Ne işe yarar |
|---|---|
| İnsan okunur belge (Swagger UI, Redoc, Scalar) | Karşı taraf denemeden okuyup anlar |
| İstemci SDK'sı (C#, TypeScript, Java…) | Elle HTTP kodu yazılmaz; sözleşme değişince derleme kırılır |
| Sunucu iskeleti | Sözleşme-önce çalışmada denetleyici şablonları |
| Sahte (mock) sunucu | Ön yüz ekibi arka uç bitmeden çalışmaya başlar |
Postman koleksiyonu / .http dosyası | Elle deneme (10. ders) |
| Ağ geçidi yapılandırması | Yol, yetki ve hız sınırı kuralları belgeden türetilir |
| Sözleşme testi ve lint | Kırıcı değişiklik CI'da yakalanır |
03.NET'te belge üretmek
Uzun yıllar bu iş Swashbuckle paketiyle yapıldı; .NET 9 ile birlikte çerçevenin kendi paketi geldi ve yeni şablonlarda varsayılan oldu:
builder.Services.AddOpenApi(); // Microsoft.AspNetCore.OpenApi (.NET 9+)
if (app.Environment.IsDevelopment())
{
app.MapOpenApi(); // /openapi/v1.json
app.MapScalarApiReference(); // ya da Swashbuckle/NSwag ile Swagger UI
}
Üçünün farkı pratikte şudur: yerleşik Microsoft.AspNetCore.OpenApi belgeyi
üretir ama arayüz sunmaz (UI için Scalar, Redoc ya da Swashbuckle'ın UI parçası
eklenir); Swashbuckle uzun geçmişi ve zengin eklenti desteğiyle hâlâ çok yaygındır;
NSwag ise belge üretmenin yanında istemci kodu üretimiyle güçlüdür.
Şema koddan nasıl çıkarılır? Bu, 5. hattın 8. dersinde bıraktığımız borcun karşılığıdır — dönüş tipi seçiminin görünür sonucu burada ortaya çıkar:
// Şema kendiliğinden çıkar: gövde tipi bellidir
public async Task<ActionResult<SiparisDto>> Getir(int no, CancellationToken ct)
// Şema ÇIKMAZ: IActionResult gövde tipini söylemez → elle bildirmek gerekir
[ProducesResponseType<SiparisDto>(StatusCodes.Status200OK)]
[ProducesResponseType<ProblemDetails>(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Getir(int no, CancellationToken ct)
// Minimal API: TypedResults birlikte hem tip hem durum kodunu bildirir
app.MapGet("/siparisler/{no:int}", async Task<Results<Ok<SiparisDto>, NotFound>> (...) => ...);
Üç ek kaynak belgeyi zenginleştirir: XML yorumları (projede
<GenerateDocumentationFile>true</GenerateDocumentationFile> açılır
ve <summary> metinleri açıklamaya dönüşür), doğrulama
öznitelikleri ([Required], [Range],
[StringLength] şemaya required, minimum,
maxLength olarak yansır — 5. hattın 9. dersinde "DataAnnotations şemaya
yansır, FluentValidation yansımaz" derken kastedilen buydu) ve uç nokta üst verisi
(WithSummary, WithTags, WithDescription).
04Hata, doğrulama ve sürümü belgeye yansıtmak
Hata gövdesini belgeye koymak çoğu API'de atlanır ve istemciyi kör bırakır. 5.
derste kurduğun ProblemDetails sözleşmesi, belgede de görünmelidir:
builder.Services.AddOpenApi(o => o.AddDocumentTransformer((belge, ctx, ct) =>
{
belge.Info.Contact = new() { Name = "Sipariş ekibi", Email = "api@ornek.local" };
return Task.CompletedTask;
}));
// Uçlarda: hangi hataların hangi gövdeyle döndüğü açıkça bildirilir
.Produces<ProblemDetails>(StatusCodes.Status409Conflict, "application/problem+json")
.ProducesValidationProblem();
Sürümlü doküman ise 6. dersteki AddApiExplorer ayarının karşılığıdır:
her API sürümü ayrı bir belge olarak yayımlanır
(/openapi/v1.json, /openapi/v2.json) ve arayüzde açılır listeden
seçilir. SubstituteApiVersionInUrl = true sayesinde belgedeki yollar
/api/v{version}/... yerine /api/v2/... olarak görünür — karşı
taraf kopyalayıp doğrudan çağırabilir.
05Kod-önce mi, sözleşme-önce mi
İki çalışma biçimi vardır ve seçim ekip yapısına göre yapılır.
| Ölçüt | Kod-önce (code-first) | Sözleşme-önce (design-first) |
|---|---|---|
| Belge nasıl doğar | Koddan üretilir | Elle yazılır, koda kaynaklık eder |
| Belge–kod tutarlılığı | Kendiliğinden | Doğrulama gerekir |
| Paralel çalışma | Ön yüz arka ucu bekler | Sahte sunucuyla hemen başlar |
| Tasarım tartışması | Kod yazıldıktan sonra | Kod yazılmadan önce |
| Kurulum maliyeti | Düşük | Yüksek (araç, süreç, disiplin) |
| Uygun olduğu yer | Tek ekip, iç API | Çok ekip, dış kurum, ihale/sözleşme |
Kamu ve kurumsal entegrasyonlarda sözleşme-önce yaklaşımının somut bir değeri vardır: OpenAPI belgesi, taraflar arasındaki teknik anlaşmanın kendisi olur. Entegrasyon dokümanı Word dosyası olarak yazıldığında kaçınılmaz biçimde kodla uyumsuz hâle gelir; makine okunur bir belge ise doğrulanabilir.
İstemci üretimi her iki biçimde de kazandırır. .NET tarafında NSwag ile:
nswag openapi2csclient /input:openapi-v2.json /classname:SiparisIstemcisi \
/namespace:Ornek.Istemci /output:SiparisIstemcisi.cs
Üretilen istemcinin asıl faydası şudur: sunucu sözleşmeyi kırıcı biçimde değiştirdiğinde, istemci projesi derlenmez. Hata çalışma zamanında değil, derleme zamanında ortaya çıkar — 6. dersteki kırıcı değişiklik tablosunun otomatik denetçisi budur. Üretilen kodun sürüm kontrolüne konup konmayacağı ekip kararıdır; yaygın uygulama, derleme adımında üretip ürün deposunda tutmamaktır.
06Kalite, güvenlik ve sapma
İyi belgenin ölçütü, karşı tarafın soru sormadan entegre olabilmesidir. Bunu sağlayan ayrıntılar:
- Örnekler. Şema tip bilgisini verir, örnek anlamı verir. Her önemli uç için gerçekçi bir istek ve yanıt örneği konur.
- Tüm yanıt kodları. Yalnız 200 belgelenmiş bir uç yarım belgedir; 400, 401, 403, 404, 409, 422 ve 429'un hangi durumda döndüğü ve gövdesinin ne olduğu yazılır.
- Enum ve nullable. Enum değerleri metin olarak listelenir (2. ders), bir alanın
nullolabilirliği şemaya doğru yansıtılır — proje<Nullable>enable</Nullable>ile derleniyorsa bu büyük ölçüde kendiliğinden olur. - Güvenlik şeması. Hangi uçların kimlik istediği ve jetonun nasıl gönderileceği
securitySchemesile bildirilir; arayüzde "Authorize" düğmesi bundan doğar. - Adlandırma tutarlılığı. Şema adları,
operationId'ler ve etiketler tutarlı olmalıdır; üretilen SDK'nın metot adları bunlardan gelir.
Güvenlik: belgeyi üretimde açık bırakmak. Swagger UI'yi ve belge uç noktasını
üretimde herkese açık bırakmak, tüm uçların, parametrelerin ve alan adlarının saldırgana
hazır bir haritasını vermektir. Kural: iç API'lerde belge üretimde kapatılır ya da
kimlikle korunur; dışa açık API'lerde belge kasıtlı olarak yayımlanır ama yönetim
uçları belgeye hiç konmaz. Ayrıca "Try it out" düğmesinin üretim ortamına istek
atabildiği unutulmamalıdır. .NET şablonlarında bu yüzden
if (app.Environment.IsDevelopment()) koşulu vardır — ve 5. hattın 13.
dersinden hatırla: ortam değişkeni yanlış ayarlanmışsa bu koşul üretimde de doğru
döner.
Sapma (drift) ve CI. Belge koddan üretiliyorsa kod ile tutarlıdır, ama sözleşme ile tutarlı olduğu anlamına gelmez: biri bir alanı sildiğinde belge de sessizce değişir. Bunu yakalamanın yolu belgeyi sürüm kontrolüne almak ve derleme hattında farkını incelemektir:
# CI adımı: belgeyi üret, depodakiyle karşılaştır
dotnet build
dotnet tool run swagger tofile --output yeni-openapi.json bin/.../Uygulama.dll v2
diff -u openapi/v2.json yeni-openapi.json || exit 1 # değiştiyse gözden geçirilsin
# Kural denetimi (lint) ve kırıcı değişiklik denetimi
spectral lint openapi/v2.json
oasdiff breaking onceki-openapi.json yeni-openapi.json
Bu üç adım, 6. dersteki sürüm disiplinini otomatik hâle getirir: alan silme ya da zorunluluk ekleme gibi kırıcı değişiklikler, birleştirme isteğinde kırmızı yanar. 18. hatta bu adımları gerçek bir hatta yerleştireceksin.
Sözleşmeyi kurduk, belgeledik ve korumaya aldık. Bir sonraki iki ders, REST'in yetmediği bir soruyu ele alıyor: istemci her ekranda farklı alan kümesi istiyorsa ne olacak? 3. derste bu soruyu sorup GraphQL'e bırakmıştık, 4. derste alan seçiminin (sparse fieldsets) belgelemeyi ve önbelleği nasıl zorlaştırdığını gördük. Şimdi alternatifin kendisine bakma sırası.
07Mini alıştırma — Sözleşmeyi görünür kıl
Yaklaşık 20 dakika · 5. hatta yazdığın servis
- Belgeyi üret:
AddOpenApi()+MapOpenApi()ekle ve/openapi/v1.jsonçıktısını incele. Kaç yol, kaç şema var? - Şema çıkarımı: bir ucun dönüş tipini
ActionResult<T>'denIActionResult'a çevir ve belgeyi tekrar üret. Yanıt şemasına ne oldu?[ProducesResponseType]ile geri kazan. - Hata gövdesi: 404 ve 409 yanıtlarını
ProblemDetailsşemasıyla belgele; doğrulama hatası içinProducesValidationProblemekle. - Açıklama:
GenerateDocumentationFile'ı aç ve bir action'a XML<summary>yaz. Belgede göründü mü? - Doğrulama yansıması: DTO'ya
[Range(1,1000)]ekle ve şemadaminimum/maximumalanlarının belirdiğini gör. - Sürümlü belge: 6. derste eklediğin v1/v2 için iki ayrı belge yayımla ve arayüzde ikisi arasında geçiş yap.
- İstemci üret: belgeden NSwag ile bir C# istemcisi üret, küçük bir konsol uygulamasından çağır. Sonra sunucuda bir alanı sil ve istemci projesini yeniden derle — hata ne zaman çıktı?
- Sapma denetimi: belgeyi depoya ekle, bir alan adını değiştir ve belgeyi
yeniden üretip
diffal. CI'da bu farkın nasıl kırmızı yanacağını bir cümleyle yaz. - Güvenlik: belge uç noktasını
IsDevelopment()koşulundan çıkar veProductionortamında çalıştır. Neyi açığa çıkardığını listele, sonra koşulu geri koy.
08Kendini sına
OpenAPI nedir, Swagger'dan farkı ne? Belgeden ne üretilir?
OpenAPI, bir HTTP API'sini JSON ya da YAML olarak tanımlayan
spesifikasyondur; Swagger ise bu standardın eski adı ve bugün etrafındaki araç
ailesinin markasıdır (Swagger UI, Editor, Codegen). Belge info,
servers, paths (uç noktalar, parametreler ve olası tüm
yanıtlar), components (yeniden kullanılan şemalar ve güvenlik tanımları,
$ref ile atıf) ve security bölümlerinden oluşur;
operationId kod üreticilerinin metot adını aldığı benzersiz alandır.
Belgenin asıl değeri üretilebilenlerdir: insan okunur belge (Swagger UI, Redoc, Scalar),
istemci SDK'sı, sunucu iskeleti, sahte sunucu (ön yüz arka ucu beklemeden çalışır),
Postman koleksiyonu ve .http dosyaları, ağ geçidi yapılandırması, sözleşme
testi ve lint. Yani OpenAPI bir belgeleme aracı değil, sözleşmenin makine okunur
hâlidir.
.NET'te şema koddan nasıl çıkarılır? Neler belgeyi zenginleştirir?
.NET 9'dan beri yerleşik Microsoft.AspNetCore.OpenApi
paketi (AddOpenApi + MapOpenApi) belgeyi üretir ama arayüz
sunmaz; UI için Scalar, Redoc ya da Swashbuckle eklenir, NSwag ise istemci üretiminde
güçlüdür. Şema büyük ölçüde dönüş tipinden çıkarılır:
ActionResult<T> gövde tipini bildirdiği için şema kendiliğinden
oluşur, IActionResult bildirmediği için
[ProducesResponseType<T>(kod)] ile elle bildirmek gerekir; minimal
API'de TypedResults ve Results<Ok<T>, NotFound> hem
tipi hem kodu birlikte bildirir. Zenginleştiren üç kaynak: XML yorumları
(GenerateDocumentationFile açılır, <summary> açıklamaya
dönüşür), doğrulama öznitelikleri ([Required], [Range],
[StringLength] şemaya required, minimum,
maxLength olarak yansır — FluentValidation kuralları yansımaz) ve uç nokta
üst verisi (WithSummary, WithTags). Hata gövdeleri de
belgelenmelidir: Produces<ProblemDetails> ve
ProducesValidationProblem. Sürümlü API'de her sürüm ayrı belge olarak
yayımlanır ve SubstituteApiVersionInUrl ile yollar somut sürümle
görünür.
Kod-önce ile sözleşme-önce arasındaki fark nedir?
Kod-önce yaklaşımda belge koddan üretilir: kurulumu ucuzdur ve belge kodla kendiliğinden tutarlıdır, ama tasarım tartışması kod yazıldıktan sonra yapılır ve ön yüz ekibi arka ucu bekler. Sözleşme-önce yaklaşımda belge elle yazılır ve koda kaynaklık eder: tasarım kod yazılmadan tartışılır, sahte sunucu sayesinde ekipler paralel çalışır; karşılığında araç, süreç ve disiplin maliyeti gelir ve belgenin kodla uyumu ayrıca doğrulanmalıdır. Tek ekipli iç API'lerde kod-önce, çok ekipli ve dış kurum entegrasyonlu işlerde sözleşme-önce uygundur. Kamu ve kurumsal işlerde sözleşme-önce'nin somut değeri, OpenAPI belgesinin taraflar arasındaki teknik anlaşmanın kendisi olmasıdır; Word dosyası olarak yazılan entegrasyon dokümanı kaçınılmaz olarak kodla uyumsuzlaşır, makine okunur belge ise doğrulanabilir. Her iki biçimde de istemci SDK'sı üretmek kazandırır: sunucu sözleşmeyi kırıcı biçimde değiştirdiğinde istemci projesi derlenmez, yani hata çalışma zamanında değil derleme zamanında çıkar.
OpenAPI ile ilgili güvenlik ve sapma riskleri neler?
Güvenlik: Swagger UI'yi ve belge uç noktasını üretimde açık
bırakmak, tüm uçların, parametrelerin ve alan adlarının saldırgana hazır bir haritasını
vermektir; ayrıca "Try it out" düğmesi üretim ortamına istek atabilir. Kural: iç API'lerde
belge üretimde kapatılır ya da kimlikle korunur; dışa açık API'lerde belge kasıtlı
yayımlanır ama yönetim uçları belgeye hiç konmaz. .NET şablonlarındaki
IsDevelopment() koşulu bunun içindir — ve ortam değişkeni yanlış
ayarlanmışsa bu koşul üretimde de doğru döner. Sapma (drift): belge koddan
üretiliyorsa kodla tutarlıdır ama sözleşmeyle tutarlı olduğu anlamına gelmez; biri
bir alanı sildiğinde belge de sessizce değişir. Çözüm belgeyi sürüm kontrolüne alıp CI'da
yeniden üretmek ve farkını incelemektir (diff), üstüne kural denetimi
(Spectral gibi bir lint) ve kırıcı değişiklik denetimi (oasdiff gibi) eklemektir. Böylece
alan silme ya da zorunluluk ekleme gibi değişiklikler birleştirme isteğinde
yakalanır — sürüm disiplininin otomatik denetçisi budur.
09Sınav köşesi
Yazılıda nasıl sorulur
(1) OpenAPI ile Swagger farkı. (2) OpenAPI belgesinin ana bölümleri.
(3) components ve $ref ne işe yarar.
(4) operationId neden önemlidir. (5) .NET'te OpenAPI belgesi nasıl
üretilir; Swashbuckle/NSwag/yerleşik paket farkı. (6) ActionResult<T>
ile IActionResult arasındaki fark belgeye nasıl yansır.
(7) [ProducesResponseType] ne zaman gerekir. (8) Kod-önce ile
sözleşme-önce karşılaştırması. (9) OpenAPI'den neler üretilebilir.
(10) Swagger UI'nin üretimde açık bırakılmasının riski. (11) Sürümlü API'de belge nasıl
yayımlanır.
Sözlüde nasıl anlatılır — 2 dakikalık taslak
Düzen: (1) Tanım — "OpenAPI, API'nin makine okunur sözleşmesidir; Swagger o
standardın eski adı ve etrafındaki araç ailesidir." (2) Değer — "belgenin amacı güzel
bir sayfa değil; ondan istemci SDK'sı, sahte sunucu, koleksiyon ve ağ geçidi ayarı
üretilebilmesidir." (3) Üretim — ".NET 9'dan beri yerleşik paketle üretiyorum; şema
büyük ölçüde dönüş tipinden çıkıyor, bu yüzden ActionResult<T> ve
minimal API'de TypedResults kullanırım, IActionResult
kullanırsam [ProducesResponseType] ile elle bildiririm." (4) Kalite —
"yalnız 200'ü değil tüm hata kodlarını ve ProblemDetails gövdesini
belgelerim, örnek koyarım, güvenlik şemasını tanımlarım." (5) Kıdem vuruşu — "belgeyi
sürüm kontrolüne alır ve CI'da yeniden üretip farkını denetlerim; lint ve kırıcı
değişiklik denetimiyle alan silme gibi değişiklikler birleştirme isteğinde kırmızı
yanar. Üretimde Swagger UI'yi açık bırakmam — tüm uçların haritasını vermek ve
'Try it out' ile üretime istek attırmak demektir. Dış entegrasyonlarda sözleşme-önce
çalışırım; OpenAPI belgesi tarafların teknik anlaşmasının kendisi olur."
