OpenAPI, bir HTTP API'sinin uç noktalarını, parametrelerini, istek ve yanıt gövdelerini, durum kodlarını ve kimlik doğrulama yöntemini makinenin de okuyabileceği tek bir JSON ya da YAML belgesinde tarif eden, dilden bağımsız bir standarttır. Swagger, bu standardın 2.0 sürümüne kadar taşıdığı addır; bugün "Swagger" denince çoğunlukla OpenAPI belgesini etkileşimli bir sayfa olarak gösteren Swagger UI arayüzü kastedilir. FastAPI bu belgeyi kodunuzdan otomatik üretir: /openapi.json adresinde belgenin kendisi, /docs adresinde Swagger UI, /redoc adresinde ReDoc görünümü yayınlanır.

Bu yazı OpenAPI'nin ne işe yaradığını, Swagger ile ilişkisini, FastAPI'nin ürettiği belgede hangi bilginin nereden geldiğini ve belgeyi summary, description, responses, operation_id gibi ayarlarla nasıl zenginleştireceğinizi çalıştırılmış örneklerle anlatıyor. Belgeyi koddan bağımsız, elle YAML olarak yazmak ise OpenAPI 3.1 YAML dosyası yazma yazısının konusu.

OpenAPI belgesi neyi anlatır, kim kullanır

OpenAPI belgesi neyi anlatır, kim kullanır: openapi, info, servers, paths

OpenAPI Şartnamesi 3.1.1'in giriş bölümü amacı şöyle özetler: doğru yazılmış bir tarif, insanların ve bilgisayarların bir hizmetin yeteneklerini kaynak koduna, ek belgelere ya da ağ trafiğini izlemeye ihtiyaç duymadan anlamasını sağlar. Aynı bölüm bu tarifin dokümantasyon üreten araçlar, farklı dillerde sunucu ve istemci kodu üreten araçlar ve test araçları tarafından kullanılabileceğini belirtir. Yani OpenAPI belgesi yalnızca bir "yardım sayfası" değildir; API'nizin makinece okunabilen sözleşmesidir.

Şartname iki terimi ayırır. OpenAPI belgesi (OpenAPI Document) şartnameye uyan tek bir JSON ya da YAML dosyasıdır. OpenAPI tarifi (OpenAPI Description) ise bir giriş belgesi ve onun başvurduğu bütün belgelerden oluşur; büyük bir API birden çok dosyaya bölünebilir. Şartname giriş belgesinin openapi.json ya da openapi.yaml olarak adlandırılmasını önerir (RECOMMENDED); FastAPI'nin varsayılan adresi de bu adla uyumludur.

Kök alanZorunlu muNe taşır
openapiEvetKullanılan şartname sürümü, örneğin 3.1.0
infoEvetAPI adı (title), belge sürümü (version), açıklama, lisans, iletişim
serversHayırSunucu adresleri; yoksa / kabul edilir
pathsKoşulluYollar ve her yoldaki işlemler (get, post, ...)
componentsKoşulluYeniden kullanılan şemalar, yanıtlar, parametreler, güvenlik şemaları
webhooksKoşulluAPI'nin istemciye göndereceği istekler
securityHayırBütün API için geçerli kimlik doğrulama gereksinimi
tagsHayırİşlemleri gruplayan etiketler ve açıklamaları

"Koşullu" yazan üç alan için şartnamenin kuralı şudur: bir tarifte paths, components ya da webhooks alanlarından en az biri bulunmalıdır. info.version ile kök düzeydeki openapi alanının karıştırılmaması gerekir: ilki sizin belgenizin sürümüdür (örneğin 1.0.0), ikincisi kullandığınız OpenAPI şartnamesinin sürümü.

Swagger ile OpenAPI arasındaki ilişki

Şartnamenin ek bölümündeki sürüm geçmişi adlandırma karışıklığını açıklar. İlk sürümler "Swagger Specification" adıyla yayımlandı; 2.0 sürümü OpenAPI Initiative'e bağışlandı ve sonraki sürümler OpenAPI adıyla çıktı. Bu yüzden eski kaynaklarda, araç adlarında ve günlük konuşmada iki kelime birbirinin yerine kullanılır.

SürümTarihNot
1.02011-08-10Swagger Specification ilk sürüm
2.02014-09-08Swagger 2.0 yayımlandı
2.02015-12-31Swagger 2.0, OpenAPI Initiative'e bağışlandı
3.0.02017-07-26OpenAPI Specification 3.0.0
3.1.02021-02-15OpenAPI Specification 3.1.0
3.1.12024-10-243.1 için düzeltme sürümü

Şartname sürüm numarasının nasıl okunacağını da tanımlar: major.minor kısmı özellik setini belirler, yama (patch) sürümleri yalnızca metindeki hataları düzeltir ve açıklık getirir. Şartnameye göre araçlar 3.1.0 ile 3.1.1 arasında ayrım yapmamalıdır. Aşağıda FastAPI'nin belgeye 3.1.0 yazdığını göreceksiniz; bu, 3.1.1 metnine göre okunan bir belgeyle aynı özellik setini kullandığı anlamına gelir.

Kod önce mi, belge önce mi

OpenAPI belgesine iki yoldan ulaşılır. Kod önce (code-first) yaklaşımda uç noktaları yazarsınız, çatı belgeyi koddan çıkarır; FastAPI tam olarak bunu yapar. Belge önce (design-first) yaklaşımda önce YAML belgesini yazıp ekiple ya da API'yi kullanacak taraflarla üzerinde anlaşırsınız, ardından kodu ona uyacak biçimde yazarsınız. İlki belgenin koddan sapmasını önler, çünkü belge her çalıştırmada yeniden üretilir. İkincisi tasarım hatalarını kod yazılmadan yakalar ve istemci ekibinin sunucu hazır olmadan çalışmaya başlamasına imkân verir. İki yaklaşım birleştirilebilir: tasarım YAML ile yapılır, uygulama yazıldıktan sonra FastAPI'nin ürettiği belge tasarım belgesiyle karşılaştırılır.

FastAPI belgeyi nasıl üretir

FastAPI belgeyi nasıl üretir: openapi ve info, summary ve operationId, tags, Yanıt kodları

Aşağıdaki uygulama bu serinin dayandığı API tasarımı rehberindeki dokümantasyon örneğinin Türkçe alan adlarıyla çalıştırılmış hâlidir. Uygulamaya başlık, açıklama ve sürüm veriliyor; Pydantic modelinin alanlarına Field(description=...) ile açıklama ekleniyor; uç noktaya summary, description, responses ve tags veriliyor. Ardından TestClient ile /openapi.json çekilip içindeki parçalar yazdırılıyor ve belge openapi_spec_validator ile doğrulanıyor. Veritabanı yerine sözlük kullanılıyor; e-posta alanı EmailStr yerine str olarak tanımlandı, çünkü EmailStr ek bir paket gerektirir.

python
from fastapi import FastAPI, HTTPException
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

app = FastAPI(
    title="Kullanıcı API",
    description="Kullanıcı ve yazı kaynaklarını yöneten örnek API",
    version="1.0.0",
)

class Kullanici(BaseModel):
    """Kullanıcı kaynağı"""
    id: int = Field(..., description="Benzersiz kullanıcı kimliği")
    email: str = Field(..., description="E-posta adresi")
    ad: str = Field(..., description="Ad soyad")

DB = {1: {"id": 1, "email": "ayse@ornek.com.tr", "ad": "Ayşe Yılmaz"}}

@app.get(
    "/v1/kullanicilar/{kullanici_id}",
    response_model=Kullanici,
    summary="Kimliğe göre kullanıcı getir",
    description="Tek bir kullanıcıyı benzersiz kimliğiyle döndürür.",
    responses={404: {"description": "Kullanıcı bulunamadı"}},
    tags=["kullanicilar"],
)
def kullanici_getir(kullanici_id: int):
    if kullanici_id not in DB:
        raise HTTPException(status_code=404, detail="Kullanıcı bulunamadı")
    return DB[kullanici_id]

c = TestClient(app)
belge = c.get("/openapi.json").json()
print(belge["openapi"], belge["info"])
islem = belge["paths"]["/v1/kullanicilar/{kullanici_id}"]["get"]
print(islem["summary"], "|", islem["operationId"])
print(islem["tags"])
print(sorted(islem["responses"]))
print(islem["parameters"][0])
print(sorted(belge["components"]["schemas"]))
print(belge["components"]["schemas"]["Kullanici"]["properties"]["email"])
for yol in ["/docs", "/redoc"]:
    r = c.get(yol)
    print(yol, r.status_code, r.headers["content-type"])

from openapi_spec_validator import validate
validate(belge)   # hata yoksa sessizce geçer
print("doğrulandı")

# çıktı:
# 3.1.0 {'title': 'Kullanıcı API', 'description': 'Kullanıcı ve yazı kaynaklarını yöneten örnek API', 'version': '1.0.0'}
# Kimliğe göre kullanıcı getir | kullanici_getir_v1_kullanicilar__kullanici_id__get
# ['kullanicilar']
# ['200', '404', '422']
# {'name': 'kullanici_id', 'in': 'path', 'required': True, 'schema': {'type': 'integer', 'title': 'Kullanici Id'}}
# ['HTTPValidationError', 'Kullanici', 'ValidationError']
# {'type': 'string', 'title': 'Email', 'description': 'E-posta adresi'}
# /docs 200 text/html; charset=utf-8
# /redoc 200 text/html; charset=utf-8
# doğrulandı

Çıktıdaki her satır belgedeki bir bilginin kaynağını gösteriyor:

  • openapi ve info: FastAPI(title=..., description=..., version=...) argümanları doğrudan info nesnesine yazıldı. Türkçe karakterler UTF-8 olarak sorunsuz geldi.
  • summary ve operationId: summary sizin yazdığınız metin. operationId ise siz vermediğiniz için işlev adı, yol ve metottan otomatik türetildi; uzun ve okunaksız bir ad ortaya çıktı.
  • tags: tags=["kullanicilar"] işlemin tags listesine yazıldı. Şartname etiketleri işlemleri kaynağa ya da başka bir ölçüte göre mantıksal olarak gruplamak için tanımlar; doküman arayüzleri işlemleri bu gruplara göre listeler. Her kaynak için bir etiket kullanmak, onlarca uç noktalı bir API'de okuyucunun aradığını bulmasını kolaylaştırır.
  • Yanıt kodları: 200 response_model'den, 404 responses sözlüğünden geldi. 422'yi siz eklemediniz: yol parametresi int olarak tanımlandığı için FastAPI doğrulama hatası yanıtını kendisi belgeledi.
  • Parametre: kullanici_id yol parametresi olarak, required: True ve integer türüyle yazıldı. Şartnameye göre yol parametrelerinde required zorunludur ve değeri true olmalıdır.
  • Şemalar: Kullanici sizin modeliniz; HTTPValidationError ve ValidationError 422 yanıtı için FastAPI'nin eklediği şemalar.
  • Alan açıklaması: Field(description=...) metni şemadaki email özelliğine geçti. Belgeyi okuyan arayüzler ve kod üreticiler bu açıklamaları alanla birlikte gösterebilir.
  • Sayfalar: /docs ve /redoc HTML döndürüyor. İki sayfanın HTML'i de /openapi.json adresine başvuruyor; yani belgeyi oradan okuyup çiziyorlar.

Son satır önemli bir güvence: FastAPI'nin ürettiği belge bağımsız bir OpenAPI doğrulayıcısından da geçti. Bu, belgeyi başka araçlara (istemci kodu üreticileri, test araçları, API ağ geçitleri) verdiğinizde yapısal bir sorunla karşılaşmayacağınız anlamına gelir.

Belgeyi zenginleştirmek: operationId, hata modeli, gizli uç noktalar

Şartname operationId için üç kural koyar: API'deki bütün işlemler arasında benzersiz olmalıdır, büyük-küçük harfe duyarlıdır ve araçlar bu değeri işlemi tanımlamak için kullanabileceğinden yaygın programlama adlandırma geleneklerine uyması önerilir. İstemci kodu üreten araçlar çoğu zaman bu adı yöntem adı olarak kullanır; kullanici_getir_v1_kullanicilar__kullanici_id__get yerine kullaniciGetir yazmak üretilen istemcinin okunurluğunu doğrudan etkiler. Aşağıdaki örnek bunu, 404 yanıtına bir gövde modeli bağlamayı, bir iç uç noktayı belgeden gizlemeyi ve doküman sayfalarını kapatmayı birlikte gösteriyor:

python
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel

app = FastAPI(title="Kullanıcı API", version="1.0.0", docs_url=None, redoc_url=None)

class Hata(BaseModel):
    detail: str

@app.get(
    "/v1/kullanicilar/{kullanici_id}",
    operation_id="kullaniciGetir",
    responses={404: {"model": Hata, "description": "Kullanıcı bulunamadı"}},
)
def kullanici_getir(kullanici_id: int):
    return {"id": kullanici_id}

@app.get("/v1/ic/saglik", include_in_schema=False)
def saglik():
    return {"durum": "ok"}

c = TestClient(app)
print(c.get("/docs").status_code, c.get("/redoc").status_code, c.get("/openapi.json").status_code)
belge = c.get("/openapi.json").json()
print(list(belge["paths"]))
islem = belge["paths"]["/v1/kullanicilar/{kullanici_id}"]["get"]
print(islem["operationId"])
print(islem["responses"]["404"])

# çıktı:
# 404 404 200
# ['/v1/kullanicilar/{kullanici_id}']
# kullaniciGetir
# {'description': 'Kullanıcı bulunamadı', 'content': {'application/json': {'schema': {'$ref': '#/components/schemas/Hata'}}}}

docs_url=None ve redoc_url=None iki arayüzü 404'e çevirdi, ama /openapi.json hâlâ 200 döndürüyor; belge kapanmadı, yalnızca onu gösteren sayfalar kapandı. include_in_schema=False sağlık kontrolü uç noktasını belgeden çıkardı, fakat uç nokta çalışmaya devam ediyor. Belgeden gizlemek bir güvenlik önlemi değildir; adresi bilen herkes isteği gönderebilir. 404 yanıtına model verilince belgeye $ref ile bağlanan bir şema eklendi; istemci artık hata gövdesinin yapısını da biliyor. Bütün uç noktalarda aynı hata şemasını kullanmak için Problem Details ya da kendi hata biçiminiz bir kez tanımlanıp her yerde başvurulabilir.

Belgeyi tamamen kapatmak gerekiyorsa FastAPI(openapi_url=None) kullanılır; denemelerimizde bu ayar /openapi.json ile birlikte /docs sayfasını da 404'e çevirdi, çünkü arayüz belgeye bağlıdır. Ayrıca işleve description vermediğinizde FastAPI işlevin belge dizesini (docstring) açıklama olarak, summary vermediğinizde ise işlev adından türettiği bir başlığı (örneğin listele için "Listele") kullanıyor. deprecated=True parametresi işlemi belgede kullanımdan kalkmış olarak işaretler; şartnameye göre istemciler bu işaretli işlemleri kullanmaktan kaçınmalıdır. Bir uç noktayı nasıl emekliye ayıracağınız Deprecation ve Sunset başlıkları yazısında anlatılıyor.

İyi bir API belgesinde neler bulunmalı

İyi bir API belgesinde neler bulunmalı: Her işlem için kısa bir summary ve gerekiyorsa davranışı anlatan bir..., Başarılı yanıtın şeması ve 401, 403, 404, 409, 422 gibi gerçekten...

Otomatik üretim belgeyi var eder, ama iyi yapmaz. Şartname Responses nesnesi için belgenin her olası durum kodunu kapsamak zorunda olmadığını, fakat başarılı yanıtı ve bilinen hataları kapsamasının beklendiğini söyler. Bu cümle iyi bir kontrol ölçütüdür. Aşağıdaki maddeler, bir okuyucunun API'nizi kaynak koduna bakmadan kullanabilmesi için gerekenleri sıralıyor:

  • Her işlem için kısa bir summary ve gerekiyorsa davranışı anlatan bir description.
  • Başarılı yanıtın şeması ve 401, 403, 404, 409, 422 gibi gerçekten dönebilecek hata kodları (durum kodu seçimi).
  • Hata gövdesinin şeması; bütün işlemlerde aynı.
  • Kimlik doğrulama yöntemi: components.securitySchemes içinde tanımlanıp security ile işlemlere bağlanır (API key, JWT Bearer).
  • Sayfalama, filtreleme ve sıralama parametrelerinin adları, varsayılanları ve üst sınırları (offset sayfalama).
  • Örnek istek ve yanıt gövdeleri; Pydantic alanlarına yazdığınız açıklamalar ve örnekler belgeye geçer.
  • Sürüm bilgisi: info.version ve URL'deki /v1 öneki (API sürümleme).
  • Kullanımdan kalkacak işlemler için deprecated işareti.

Doküman sayfaları üretimde açık kalmalı mı

Bu sorunun tek doğru cevabı yok; API'nin kime açık olduğuna bağlı. Herkese açık bir API için etkileşimli belge, kullanıcının ilk dakikada başarılı bir istek göndermesinin en kısa yoludur ve kapatmak için bir neden yoktur. Yalnızca kendi ön yüzünüzün kullandığı bir iç API'de ise belgenin herkese açık olması saldırı yüzeyinin haritasını vermek anlamına gelebilir; bu durumda belge yalnızca iç ağdan ya da kimlik doğrulamasının arkasından sunulabilir, ya da derleme sırasında dosyaya yazılıp iç dokümantasyon sistemine konabilir. Belgeyi gizlemenin uç noktaları korumadığını, korumanın kimlik doğrulama ve yetkilendirmeyle sağlandığını yeniden hatırlatalım. FastAPI uygulamasını sunucuya yerleştirme adımları FastAPI, Uvicorn ve Nginx ile yayın yazısında.

Sık yapılan hatalar

  • Yalnızca 200'ü belgelemek: İstemci hangi hataları ele alması gerektiğini bilemez.
  • Otomatik operationId'ye razı olmak: Üretilen istemci kodunda okunaksız yöntem adları çıkar.
  • Belgeyi kodla senkron tutmamak: Elle yazılmış ve sonra güncellenmemiş bir belge, hiç olmayan bir belgeden daha yanıltıcıdır. Kod önce yaklaşımında bu sorun büyük ölçüde ortadan kalkar.
  • Gizlemeyi güvenlik sanmak: include_in_schema=False ya da docs_url=None uç noktayı kapatmaz.
  • Şema yerine serbest sözlük döndürmek: response_model verilmeyen uç noktaların yanıt şeması belgede boş kalır.
  • Belgeyi doğrulamamak: Özellikle elle eklenen parçalar şartnameye aykırı olabilir; bir doğrulayıcıyla denetlemek dakikalar sürer.

Sık Sorulan Sorular

Swagger ile OpenAPI aynı şey mi?

Şartname açısından Swagger, OpenAPI'nin 2.0 sürümüne kadarki adıdır. Bugün Swagger adı daha çok Swagger UI gibi araçlar için kullanılır; standardın kendisinin adı OpenAPI Specification'dır.

FastAPI hangi OpenAPI sürümünü üretiyor?

Denediğimiz FastAPI 0.128 sürümü belgeye openapi: 3.1.0 yazdı. Şartnameye göre 3.1.0 ile 3.1.1 aynı özellik setini paylaşır.

/docs ile /redoc arasındaki fark nedir?

İkisi de aynı /openapi.json belgesini gösterir. /docs Swagger UI'dır ve istekleri sayfadan gönderip denemenize izin verir; /redoc ReDoc'tur ve belgeyi okunaklı bir referans sayfası olarak sunar.

Belgeyi bir dosyaya nasıl kaydederim?

app.openapi() çağrısı belgeyi bir Python sözlüğü olarak döndürür; bunu json.dump ile dosyaya yazabilir ya da yukarıdaki gibi TestClient ile /openapi.json adresinden alabilirsiniz.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: REST API tasarımı öğrenme rehberi · OpenAPI 3.1 YAML yazma · Problem Details · Deprecation ve Sunset · tasarım kontrol listesi · FastAPI deploy