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 Ş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 alan | Zorunlu mu | Ne taşır |
|---|---|---|
| openapi | Evet | Kullanılan şartname sürümü, örneğin 3.1.0 |
| info | Evet | API adı (title), belge sürümü (version), açıklama, lisans, iletişim |
| servers | Hayır | Sunucu adresleri; yoksa / kabul edilir |
| paths | Koşullu | Yollar ve her yoldaki işlemler (get, post, ...) |
| components | Koşullu | Yeniden kullanılan şemalar, yanıtlar, parametreler, güvenlik şemaları |
| webhooks | Koşullu | API'nin istemciye göndereceği istekler |
| security | Hayır | Bütün API için geçerli kimlik doğrulama gereksinimi |
| tags | Hayı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üm | Tarih | Not |
|---|---|---|
| 1.0 | 2011-08-10 | Swagger Specification ilk sürüm |
| 2.0 | 2014-09-08 | Swagger 2.0 yayımlandı |
| 2.0 | 2015-12-31 | Swagger 2.0, OpenAPI Initiative'e bağışlandı |
| 3.0.0 | 2017-07-26 | OpenAPI Specification 3.0.0 |
| 3.1.0 | 2021-02-15 | OpenAPI Specification 3.1.0 |
| 3.1.1 | 2024-10-24 | 3.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

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.
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ğrudaninfonesnesine yazıldı. Türkçe karakterler UTF-8 olarak sorunsuz geldi. - summary ve operationId:
summarysizin yazdığınız metin.operationIdise 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şlemintagslistesine 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, 404responsessözlüğünden geldi. 422'yi siz eklemediniz: yol parametresiintolarak tanımlandığı için FastAPI doğrulama hatası yanıtını kendisi belgeledi. - Parametre:
kullanici_idyol parametresi olarak,required: Trueveintegertürüyle yazıldı. Şartnameye göre yol parametrelerinderequiredzorunludur ve değeritrueolmalıdır. - Şemalar:
Kullanicisizin modeliniz;HTTPValidationErrorveValidationError422 yanıtı için FastAPI'nin eklediği şemalar. - Alan açıklaması:
Field(description=...)metni şemadakiemailözelliğine geçti. Belgeyi okuyan arayüzler ve kod üreticiler bu açıklamaları alanla birlikte gösterebilir. - Sayfalar:
/docsve/redocHTML döndürüyor. İki sayfanın HTML'i de/openapi.jsonadresine 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:
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ı

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
summaryve gerekiyorsa davranışı anlatan birdescription. - 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.securitySchemesiçinde tanımlanıpsecurityile 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.versionve URL'deki/v1öneki (API sürümleme). - Kullanımdan kalkacak işlemler için
deprecatediş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=Falseya dadocs_url=Noneuç noktayı kapatmaz. - Şema yerine serbest sözlük döndürmek:
response_modelverilmeyen 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