Skip to content

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ığı
  • ProblemDetails ve 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:

ÜretilenNe 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 iskeletiSö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 lintKı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çütKod-önce (code-first)Sözleşme-önce (design-first)
Belge nasıl doğarKoddan üretilirElle yazılır, koda kaynaklık eder
Belge–kod tutarlılığıKendiliğindenDoğrulama gerekir
Paralel çalışmaÖn yüz arka ucu beklerSahte sunucuyla hemen başlar
Tasarım tartışmasıKod yazıldıktan sonraKod yazılmadan önce
Kurulum maliyetiDüşükYüksek (araç, süreç, disiplin)
Uygun olduğu yerTek 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 null olabilirliğ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 securitySchemes ile 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

  1. Belgeyi üret: AddOpenApi() + MapOpenApi() ekle ve /openapi/v1.json çıktısını incele. Kaç yol, kaç şema var?
  2. Şema çıkarımı: bir ucun dönüş tipini ActionResult<T>'den IActionResult'a çevir ve belgeyi tekrar üret. Yanıt şemasına ne oldu? [ProducesResponseType] ile geri kazan.
  3. Hata gövdesi: 404 ve 409 yanıtlarını ProblemDetails şemasıyla belgele; doğrulama hatası için ProducesValidationProblem ekle.
  4. Açıklama: GenerateDocumentationFile'ı aç ve bir action'a XML <summary> yaz. Belgede göründü mü?
  5. Doğrulama yansıması: DTO'ya [Range(1,1000)] ekle ve şemada minimum/maximum alanlarının belirdiğini gör.
  6. 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.
  7. İ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ı?
  8. Sapma denetimi: belgeyi depoya ekle, bir alan adını değiştir ve belgeyi yeniden üretip diff al. CI'da bu farkın nasıl kırmızı yanacağını bir cümleyle yaz.
  9. Güvenlik: belge uç noktasını IsDevelopment() koşulundan çıkar ve Production ortamı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."