Response Model - Dönüş Tipi¶
🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri
Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝
Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖
Yapay zekâyı daha iyi yönlendirmemize yardımcı olarak bu çeviriyi iyileştirebilirsiniz.
Path operation function dönüş tipini (return type) type annotation ile belirtip response için kullanılacak tipi tanımlayabilirsiniz.
Fonksiyon parametreleri için input data’da kullandığınız type annotations yaklaşımının aynısını burada da kullanabilirsiniz; Pydantic model’leri, list’ler, dict’ler, integer, boolean gibi skaler değerler vb.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.post("/items/")
async def create_item(item: Item) -> Item:
return item
@app.get("/items/")
async def read_items() -> list[Item]:
return [
Item(name="Portal Gun", price=42.0),
Item(name="Plumbus", price=32.0),
]
FastAPI bu dönüş tipini şunlar için kullanır:
- Dönen veriyi doğrulamak (validate).
- Veri geçersizse (ör. bir field eksikse), bu sizin uygulama kodunuzun bozuk olduğu, olması gerekeni döndürmediği anlamına gelir; bu yüzden yanlış veri döndürmek yerine server error döner. Böylece siz ve client’larınız, beklenen veri ve veri şeklinin geleceğinden emin olabilirsiniz.
- OpenAPI’deki path operation içine response için bir JSON Schema eklemek.
- Bu, otomatik dokümantasyon tarafından kullanılır.
- Ayrıca otomatik client code generation araçları tarafından da kullanılır.
Ama en önemlisi:
- Çıktı verisini, dönüş tipinde tanımlı olana göre sınırlar ve filtreler.
- Bu, özellikle güvenlik açısından önemlidir; aşağıda daha fazlasını göreceğiz.
response_model Parametresi¶
Bazı durumlarda, tam olarak dönüş tipinin söylediği gibi olmayan bir veriyi döndürmeniz gerekebilir ya da isteyebilirsiniz.
Örneğin, bir dict veya bir veritabanı objesi döndürmek isteyip, ama onu bir Pydantic model olarak declare etmek isteyebilirsiniz. Böylece Pydantic model, döndürdüğünüz obje (ör. dict veya veritabanı objesi) için dokümantasyon, doğrulama vb. işlerin tamamını yapar.
Eğer dönüş tipi annotation’ını eklerseniz, araçlar ve editörler (doğru şekilde) fonksiyonunuzun, declare ettiğiniz tipten (ör. Pydantic model) farklı bir tip (ör. dict) döndürdüğünü söyleyip hata verir.
Bu gibi durumlarda, dönüş tipi yerine path operation decorator parametresi olan response_model’i kullanabilirsiniz.
response_model parametresini herhangi bir path operation içinde kullanabilirsiniz:
@app.get()@app.post()@app.put()@app.delete()- vb.
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
return item
@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
return [
{"name": "Portal Gun", "price": 42.0},
{"name": "Plumbus", "price": 32.0},
]
Not
response_model’in "decorator" metodunun (get, post vb.) bir parametresi olduğuna dikkat edin. Body ve diğer parametreler gibi, sizin path operation function’ınızın parametresi değildir.
response_model, Pydantic model field’ı için declare edeceğiniz aynı tipi alır; yani bir Pydantic model olabilir ama örneğin List[Item] gibi Pydantic model’lerden oluşan bir list de olabilir.
FastAPI bu response_model’i; dokümantasyon, doğrulama vb. her şey için ve ayrıca çıktı verisini tip tanımına göre dönüştürmek ve filtrelemek için kullanır.
İpucu
Editörünüzde, mypy vb. ile sıkı type kontrolü yapıyorsanız, fonksiyon dönüş tipini Any olarak declare edebilirsiniz.
Böylece editöre bilerek her şeyi döndürebileceğinizi söylemiş olursunuz. Ancak FastAPI, response_model ile dokümantasyon, doğrulama, filtreleme vb. işlemleri yine de yapar.
response_model Önceliği¶
Hem dönüş tipi hem de response_model declare ederseniz, FastAPI’de response_model önceliklidir ve o kullanılır.
Böylece, response model’den farklı bir tip döndürdüğünüz durumlarda bile editör ve mypy gibi araçlar için fonksiyonlarınıza doğru type annotation’lar ekleyebilir, aynı zamanda FastAPI’nin response_model üzerinden veri doğrulama, dokümantasyon vb. yapmasını sağlayabilirsiniz.
Ayrıca response_model=None kullanarak, ilgili path operation için response model oluşturulmasını devre dışı bırakabilirsiniz. Bu, Pydantic field’ı olarak geçerli olmayan şeyler için type annotation eklediğinizde gerekebilir; aşağıdaki bölümlerden birinde bunun örneğini göreceksiniz.
Aynı input verisini geri döndürmek¶
Burada UserIn adında bir model declare ediyoruz; bu model plaintext bir password içerecek:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
return user
Bilgi
EmailStr kullanmak için önce email-validator paketini kurun.
Bir virtual environment oluşturduğunuzdan, onu aktive ettiğinizden emin olun ve ardından örneğin şöyle kurun:
$ pip install email-validator
veya şöyle:
$ pip install "pydantic[email]"
Bu model ile hem input’u declare ediyoruz hem de output’u aynı model ile declare ediyoruz:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
return user
Artık bir browser password ile user oluşturduğunda, API response içinde aynı password’ü geri döndürecek.
Bu örnekte sorun olmayabilir; çünkü password’ü gönderen kullanıcı zaten aynı kişi.
Ancak aynı modeli başka bir path operation için kullanırsak, kullanıcının password’lerini her client’a gönderiyor olabiliriz.
Danger
Tüm riskleri bildiğinizden ve ne yaptığınızdan emin olmadığınız sürece, bir kullanıcının plain password’ünü asla saklamayın ve bu şekilde response içinde göndermeyin.
Bir output modeli ekleyin¶
Bunun yerine, plaintext password içeren bir input modeli ve password’ü içermeyen bir output modeli oluşturabiliriz:
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
Burada path operation function password içeren aynı input user’ı döndürüyor olsa bile:
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
...response_model olarak, password’ü içermeyen UserOut modelimizi declare ettik:
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
Dolayısıyla FastAPI, output model’de declare edilmemiş tüm verileri (Pydantic kullanarak) filtrelemekle ilgilenir.
response_model mi Return Type mı?¶
Bu durumda iki model farklı olduğu için fonksiyon dönüş tipini UserOut olarak annotate etseydik, editör ve araçlar farklı class’lar olduğu için geçersiz bir tip döndürdüğümüzü söyleyip hata verecekti.
Bu yüzden bu örnekte response_model parametresinde declare etmek zorundayız.
...ama bunu nasıl aşabileceğinizi görmek için aşağıyı okumaya devam edin.
Return Type ve Veri Filtreleme¶
Önceki örnekten devam edelim. Fonksiyonu tek bir tip ile annotate etmek istiyoruz; ama fonksiyondan gerçekte daha fazla veri içeren bir şey döndürebilmek istiyoruz.
FastAPI’nin response model’i kullanarak veriyi filtrelemeye devam etmesini istiyoruz. Yani fonksiyon daha fazla veri döndürse bile response, sadece response model’de declare edilmiş field’ları içersin.
Önceki örnekte class’lar farklı olduğu için response_model parametresini kullanmak zorundaydık. Ancak bu, editör ve araçların fonksiyon dönüş tipi kontrolünden gelen desteğini alamadığımız anlamına da geliyor.
Ama bu tarz durumların çoğunda modelin amacı, bu örnekteki gibi bazı verileri filtrelemek/kaldırmak olur.
Bu gibi durumlarda class’lar ve inheritance kullanarak, fonksiyon type annotations sayesinde editör ve araçlarda daha iyi destek alabilir, aynı zamanda FastAPI’nin veri filtrelemesini de koruyabiliriz.
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class BaseUser(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
class UserIn(BaseUser):
password: str
@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
return user
Bununla birlikte, code type’lar açısından doğru olduğu için editörler ve mypy araç desteği verir; ayrıca FastAPI’den veri filtrelemeyi de alırız.
Bu nasıl çalışıyor? Bir bakalım. 🤓
Type Annotations ve Araç Desteği¶
Önce editörler, mypy ve diğer araçlar bunu nasıl görür, ona bakalım.
BaseUser temel field’lara sahiptir. Ardından UserIn, BaseUser’dan miras alır ve password field’ını ekler; yani iki modelin field’larının tamamını içerir.
Fonksiyonun dönüş tipini BaseUser olarak annotate ediyoruz ama gerçekte bir UserIn instance’ı döndürüyoruz.
Editör, mypy ve diğer araçlar buna itiraz etmez; çünkü typing açısından UserIn, BaseUser’ın subclass’ıdır. Bu da, bir BaseUser bekleniyorken UserIn’in geçerli bir tip olduğu anlamına gelir.
FastAPI Veri Filtreleme¶
FastAPI açısından ise dönüş tipini görür ve döndürdüğünüz şeyin yalnızca tipte declare edilen field’ları içerdiğinden emin olur.
FastAPI, Pydantic ile içeride birkaç işlem yapar; böylece class inheritance kurallarının dönen veri filtrelemede aynen kullanılmasına izin vermez. Aksi halde beklediğinizden çok daha fazla veriyi response’ta döndürebilirdiniz.
Bu sayede iki dünyanın da en iyisini alırsınız: araç desteği veren type annotations ve veri filtreleme.
Dokümanlarda görün¶
Otomatik dokümanları gördüğünüzde, input model ve output model’in her birinin kendi JSON Schema’sına sahip olduğunu kontrol edebilirsiniz:

Ve her iki model de etkileşimli API dokümantasyonunda kullanılır:

Diğer Return Type Annotation’ları¶
Bazı durumlarda Pydantic field olarak geçerli olmayan bir şey döndürebilir ve bunu fonksiyonda annotate edebilirsiniz; amaç sadece araçların (editör, mypy vb.) sağladığı desteği almaktır.
Doğrudan Response Döndürmek¶
En yaygın durum, ileri seviye dokümanlarda daha sonra anlatıldığı gibi doğrudan bir Response döndürmektir.
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, RedirectResponse
app = FastAPI()
@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response:
if teleport:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
return JSONResponse(content={"message": "Here's your interdimensional portal."})
🤓 Other versions and variants
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, RedirectResponse
app = FastAPI()
@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response:
if teleport:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
return JSONResponse(content={"message": "Here's your interdimensional portal."})
Bu basit durum FastAPI tarafından otomatik olarak ele alınır; çünkü dönüş tipi annotation’ı Response class’ıdır (veya onun bir subclass’ı).
Araçlar da memnun olur; çünkü hem RedirectResponse hem JSONResponse, Response’un subclass’ıdır. Yani type annotation doğrudur.
Bir Response Subclass’ını Annotate Etmek¶
Type annotation içinde Response’un bir subclass’ını da kullanabilirsiniz:
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/teleport")
async def get_teleport() -> RedirectResponse:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
🤓 Other versions and variants
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/teleport")
async def get_teleport() -> RedirectResponse:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
Bu da çalışır; çünkü RedirectResponse, Response’un subclass’ıdır ve FastAPI bu basit durumu otomatik olarak yönetir.
Geçersiz Return Type Annotation’ları¶
Ancak geçerli bir Pydantic tipi olmayan başka rastgele bir obje (ör. bir veritabanı objesi) döndürür ve fonksiyonu da öyle annotate ederseniz, FastAPI bu type annotation’dan bir Pydantic response model oluşturmaya çalışır ve başarısız olur.
Aynı şey, farklı tipler arasında bir union kullandığınızda ve bu tiplerden biri veya birkaçı geçerli bir Pydantic tipi değilse de olur; örneğin şu kullanım patlar 💥:
from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response | dict:
if teleport:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
return {"message": "Here's your interdimensional portal."}
...bu, type annotation Pydantic tipi olmadığı ve tek bir Response class’ı (veya subclass’ı) olmadığı için başarısız olur; bu, bir Response ile bir dict arasında union’dır (ikiden herhangi biri).
Response Model’i Devre Dışı Bırakmak¶
Yukarıdaki örnekten devam edersek; FastAPI’nin varsayılan olarak yaptığı veri doğrulama, dokümantasyon, filtreleme vb. işlemleri istemiyor olabilirsiniz.
Ancak yine de editörler ve type checker’lar (ör. mypy) gibi araçların desteğini almak için fonksiyonda dönüş tipi annotation’ını korumak isteyebilirsiniz.
Bu durumda response_model=None ayarlayarak response model üretimini devre dışı bırakabilirsiniz:
from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Response | dict:
if teleport:
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
return {"message": "Here's your interdimensional portal."}
Bu, FastAPI’nin response model üretimini atlamasını sağlar; böylece FastAPI uygulamanızı etkilemeden ihtiyacınız olan herhangi bir return type annotation’ını kullanabilirsiniz. 🤓
Response Model encoding parametreleri¶
Response model’inizde şu şekilde default değerler olabilir:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
tags: list[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
description: Union[str, None] = None(veya Python 3.10’dastr | None = None) için defaultNone’dır.tax: float = 10.5için default10.5’tir.tags: List[str] = []için default, boş bir list’tir:[].
Ancak gerçekte kaydedilmedilerse, bunları sonuçtan çıkarmak isteyebilirsiniz.
Örneğin NoSQL veritabanında çok sayıda optional attribute içeren modelleriniz varsa, default değerlerle dolu çok uzun JSON response’ları göndermek istemeyebilirsiniz.
response_model_exclude_unset parametresini kullanın¶
Path operation decorator parametresi olarak response_model_exclude_unset=True ayarlayabilirsiniz:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
tags: list[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
böylece response’a default değerler dahil edilmez; yalnızca gerçekten set edilmiş değerler gelir.
Dolayısıyla ID’si foo olan item için bu path operation’a request atarsanız, response (default değerler olmadan) şöyle olur:
{
"name": "Foo",
"price": 50.2
}
Bilgi
Ayrıca şunları da kullanabilirsiniz:
response_model_exclude_defaults=Trueresponse_model_exclude_none=True
Bunlar, exclude_defaults ve exclude_none için Pydantic dokümanlarında anlatıldığı gibidir.
Default’u olan field’lar için değer içeren data¶
Ama data’nız modelde default değeri olan field’lar için değer içeriyorsa, örneğin ID’si bar olan item gibi:
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2
}
bunlar response’a dahil edilir.
Default değerlerle aynı değerlere sahip data¶
Eğer data, default değerlerle aynı değerlere sahipse, örneğin ID’si baz olan item gibi:
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
FastAPI yeterince akıllıdır (aslında Pydantic yeterince akıllıdır) ve description, tax, tags default ile aynı olsa bile bunların explicit olarak set edildiğini (default’tan alınmadığını) anlar.
Bu yüzden JSON response içinde yer alırlar.
İpucu
Default değerlerin yalnızca None olmak zorunda olmadığını unutmayın.
Bir list ([]), 10.5 gibi bir float vb. olabilirler.
response_model_include ve response_model_exclude¶
Ayrıca path operation decorator parametreleri response_model_include ve response_model_exclude’u da kullanabilirsiniz.
Bunlar; dahil edilecek attribute isimlerini (geri kalanını atlayarak) ya da hariç tutulacak attribute isimlerini (geri kalanını dahil ederek) belirten str değerlerinden oluşan bir set alır.
Tek bir Pydantic model’iniz varsa ve output’tan bazı verileri hızlıca çıkarmak istiyorsanız, bu yöntem pratik bir kısayol olabilir.
İpucu
Ancak yine de, bu parametreler yerine yukarıdaki yaklaşımı (birden fazla class kullanmayı) tercih etmeniz önerilir.
Çünkü response_model_include veya response_model_exclude ile bazı attribute’ları atlıyor olsanız bile, uygulamanızın OpenAPI’sinde (ve dokümanlarda) üretilen JSON Schema hâlâ tam modelin JSON Schema’sı olacaktır.
Bu durum, benzer şekilde çalışan response_model_by_alias için de geçerlidir.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
"baz": {
"name": "Baz",
"description": "There goes my baz",
"price": 50.2,
"tax": 10.5,
},
}
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
return items[item_id]
İpucu
{"name", "description"} sözdizimi, bu iki değere sahip bir set oluşturur.
Bu, set(["name", "description"]) ile eşdeğerdir.
set yerine list kullanmak¶
Yanlışlıkla set yerine list veya tuple kullanırsanız, FastAPI bunu yine set’e çevirir ve doğru şekilde çalışır:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
"baz": {
"name": "Baz",
"description": "There goes my baz",
"price": 50.2,
"tax": 10.5,
},
}
@app.get(
"/items/{item_id}/name",
response_model=Item,
response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
return items[item_id]
@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
return items[item_id]
Özet¶
Response model’leri tanımlamak ve özellikle private data’nın filtrelendiğinden emin olmak için path operation decorator parametresi response_model’i kullanın.
Yalnızca explicit olarak set edilmiş değerleri döndürmek için response_model_exclude_unset kullanın.