์๋ต ๋ชจ๋ธ¶
์ด๋ค ๊ฒฝ๋ก ๋์์ด๋ ๋งค๊ฐ๋ณ์ response_model
๋ฅผ ์ฌ์ฉํ์ฌ ์๋ต์ ์ํ ๋ชจ๋ธ์ ์ ์ธํ ์ ์์ต๋๋ค:
@app.get()
@app.post()
@app.put()
@app.delete()
- ๊ธฐํ.
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: List[str] = []
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
return item
์ฐธ๊ณ
response_model
์ "๋ฐ์ฝ๋ ์ดํฐ" ๋ฉ์๋(get
, post
, ๋ฑ)์ ๋งค๊ฐ๋ณ์์
๋๋ค. ๋ชจ๋ ๋งค๊ฐ๋ณ์๋ค๊ณผ ๋ณธ๋ฌธ(body)์ฒ๋ผ ๊ฒฝ๋ก ๋์ ํจ์๊ฐ ์๋๋๋ค.
Pydantic ๋ชจ๋ธ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ ์ธํ ๊ฒ๊ณผ ๋์ผํ ํ์
์ ์์ ํ๋ฏ๋ก Pydantic ๋ชจ๋ธ์ด ๋ ์ ์์ง๋ง, List[Item]
๊ณผ ๊ฐ์ด Pydantic ๋ชจ๋ธ๋ค์ list
์ผ ์๋ ์์ต๋๋ค.
FastAPI๋ ์ด response_model
๋ฅผ ์ฌ์ฉํ์ฌ:
- ์ถ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ํ์ ์ ์ธ์ผ๋ก ๋ณํ.
- ๋ฐ์ดํฐ ๊ฒ์ฆ.
- OpenAPI ๊ฒฝ๋ก ๋์์ ์๋ต์ JSON ์คํค๋ง ์ถ๊ฐ.
- ์๋ ์์ฑ ๋ฌธ์ ์์คํ ์ ์ฌ์ฉ.
ํ์ง๋ง ๊ฐ์ฅ ์ค์ํ ๊ฒ์:
- ํด๋น ๋ชจ๋ธ์ ์ถ๋ ฅ ๋ฐ์ดํฐ ์ ํ. ์ด๊ฒ์ด ์ผ๋ง๋ ์ค์ํ์ง ์๋์์ ๋ณผ ๊ฒ์ ๋๋ค.
๊ธฐ์ ์ธ๋ถ์ฌํญ
์๋ต ๋ชจ๋ธ์ ํจ์์ ํ์
์ด๋
ธํ
์ด์
๋์ ์ด ๋งค๊ฐ๋ณ์๋ก ์ ์ธํ๋๋ฐ, ๊ฒฝ๋ก ํจ์๊ฐ ์ค์ ์๋ต ๋ชจ๋ธ์ ๋ฐํํ์ง ์๊ณ dict
, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ฒด๋ ๊ธฐํ ๋ค๋ฅธ ๋ชจ๋ธ์ response_model
์ ์ฌ์ฉํ์ฌ ํ๋ ์ ํ๊ณผ ์ง๋ ฌํ๋ฅผ ์ํํ๊ณ ๋ฐํํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค
๋์ผํ ์ ๋ ฅ ๋ฐ์ดํฐ ๋ฐํ¶
์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ํฌํจํ๋ UserIn
๋ชจ๋ธ์ ์ ์ธํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
return user
๊ทธ๋ฆฌ๊ณ ์ด ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ์ ๋ ฅ์ ์ ์ธํ๊ณ ๊ฐ์ ๋ชจ๋ธ๋ก ์ถ๋ ฅ์ ์ ์ธํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
# Don't do this in production!
@app.post("/user/", response_model=UserIn)
async def create_user(user: UserIn):
return user
์ด์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋น๋ฐ๋ฒํธ๋ก ์ฌ์ฉ์๋ฅผ ๋ง๋ค ๋๋ง๋ค API๋ ์๋ต์ผ๋ก ๋์ผํ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐํํฉ๋๋ค.
์ด ๊ฒฝ์ฐ, ์ฌ์ฉ์๊ฐ ์ค์ค๋ก ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ์ ํ๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๊ฐ ๋์ง ์์ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๋์ผํ ๋ชจ๋ธ์ ๋ค๋ฅธ ๊ฒฝ๋ก ๋์์์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ์ฌ์ฉ์์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ์ ํ ์ ์์ต๋๋ค.
์ํ
์ ๋๋ก ์ฌ์ฉ์์ ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅํ๊ฑฐ๋ ์๋ต์ผ๋ก ๋ฐ์ ํ์ง ๋ง์ญ์์ค.
์ถ๋ ฅ ๋ชจ๋ธ ์ถ๊ฐ¶
๋์ ํ๋ฌธ ๋น๋ฐ๋ฒํธ๋ก ์ ๋ ฅ ๋ชจ๋ธ์ ๋ง๋ค๊ณ ํด๋น ๋น๋ฐ๋ฒํธ ์์ด ์ถ๋ ฅ ๋ชจ๋ธ์ ๋ง๋ค ์ ์์ต๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user
์ฌ๊ธฐ์ ๊ฒฝ๋ก ๋์ ํจ์๊ฐ ๋น๋ฐ๋ฒํธ๋ฅผ ํฌํจํ๋ ๋์ผํ ์ ๋ ฅ ์ฌ์ฉ์๋ฅผ ๋ฐํํ ์ง๋ผ๋:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user
...response_model
์ UserOut
๋ชจ๋ธ๋ก ์ ์ธํ๊ธฐ ๋๋ฌธ์ ๋น๋ฐ๋ฒํธ๋ฅผ ํฌํจํ์ง ์์ต๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: Union[str, None] = None
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
return user
๋ฐ๋ผ์ FastAPI๋ ์ถ๋ ฅ ๋ชจ๋ธ์์ ์ ์ธํ์ง ์์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ (Pydantic์ ์ฌ์ฉํ์ฌ) ํํฐ๋งํฉ๋๋ค.
๋ฌธ์์์ ๋ณด๊ธฐ¶
์๋ ์์ฑ ๋ฌธ์๋ฅผ ๋ณด๋ฉด ์ ๋ ฅ ๋ชจ๋ธ๊ณผ ์ถ๋ ฅ ๋ชจ๋ธ์ด ๊ฐ์์ JSON ์คํค๋ง๋ฅผ ๊ฐ์ง๊ณ ์์์ ํ์ธํ ์ ์์ต๋๋ค:
๊ทธ๋ฆฌ๊ณ ๋ ๋ชจ๋ธ ๋ชจ๋ ๋ํํ API ๋ฌธ์์ ์ฌ์ฉ๋ฉ๋๋ค:
์๋ต ๋ชจ๋ธ ์ธ์ฝ๋ฉ ๋งค๊ฐ๋ณ์¶
์๋ต ๋ชจ๋ธ์ ์๋์ ๊ฐ์ด ๊ธฐ๋ณธ๊ฐ์ ๊ฐ์ง ์ ์์ต๋๋ค:
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[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: Optional[str] = None
์ ๊ธฐ๋ณธ๊ฐ์ผ๋กNone
์ ๊ฐ์ต๋๋ค.tax: float = 10.5
๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก10.5
๋ฅผ ๊ฐ์ต๋๋ค.tags: List[str] = []
๋น ๋ฆฌ์คํธ์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก:[]
.
๊ทธ๋ฌ๋ ์ค์ ๋ก ์ ์ฅ๋์ง ์์์ ๊ฒฝ์ฐ ๊ฒฐ๊ณผ์์ ๊ฐ์ ์๋ตํ๊ณ ์ถ์ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ง์ ์ ํ์ ์์ฑ์ด ์๋ ๋ชจ๋ธ์ด ์์ง๋ง, ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ฐ๋ ์ฐฌ ๋งค์ฐ ๊ธด JSON ์๋ต์ ๋ณด๋ด๊ณ ์ถ์ง ์์ต๋๋ค.
response_model_exclude_unset
๋งค๊ฐ๋ณ์ ์ฌ์ฉ¶
๊ฒฝ๋ก ๋์ ๋ฐ์ฝ๋ ์ดํฐ ๋งค๊ฐ๋ณ์๋ฅผ response_model_exclude_unset=True
๋ก ์ค์ ํ ์ ์์ต๋๋ค:
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[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]
์ด๋ฌํ ๊ธฐ๋ณธ๊ฐ์ ์๋ต์ ํฌํจ๋์ง ์๊ณ ์ค์ ๋ก ์ค์ ๋ ๊ฐ๋ง ํฌํจ๋ฉ๋๋ค.
๋ฐ๋ผ์ ํด๋น ๊ฒฝ๋ก ๋์์ ID๊ฐ foo
์ธ ํญ๋ชฉ(items)์ ์์ฒญ์ผ๋ก ๋ณด๋ด๋ฉด (๊ธฐ๋ณธ๊ฐ์ ์ ์ธํ) ์๋ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
{
"name": "Foo",
"price": 50.2
}
์ ๋ณด
FastAPI๋ ์ด๋ฅผ ์ํด Pydantic ๋ชจ๋ธ์ .dict()
์ exclude_unset
๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ ๋ณด
์๋ ๋ํ ์ฌ์ฉํ ์ ์์ต๋๋ค:
response_model_exclude_defaults=True
response_model_exclude_none=True
Pydantic ๋ฌธ์์์ exclude_defaults
๋ฐ exclude_none
์ ๋ํด ์ค๋ช
ํ ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ธฐ๋ณธ๊ฐ์ด ์๋ ํ๋๋ฅผ ๊ฐ๋ ๊ฐ์ ๋ฐ์ดํฐ¶
ํ์ง๋ง ๋ชจ๋ธ์ ํ๋๊ฐ ๊ธฐ๋ณธ๊ฐ์ด ์์ด๋ ID๊ฐ bar
์ธ ํญ๋ชฉ(items)์ฒ๋ผ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ ๊ฐ๋๋ค๋ฉด:
{
"name": "Bar",
"description": "The bartenders",
"price": 62,
"tax": 20.2
}
์๋ต์ ํด๋น ๊ฐ๋ค์ด ํฌํจ๋ฉ๋๋ค.
๊ธฐ๋ณธ๊ฐ๊ณผ ๋์ผํ ๊ฐ์ ๊ฐ๋ ๋ฐ์ดํฐ¶
If the data has the same values as the default ones, like the item with ID baz
:
ID๊ฐ baz
์ธ ํญ๋ชฉ(items)์ฒ๋ผ ๊ธฐ๋ณธ๊ฐ๊ณผ ๋์ผํ ๊ฐ์ ๊ฐ๋๋ค๋ฉด:
{
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": []
}
description
, tax
๊ทธ๋ฆฌ๊ณ tags
๊ฐ ๊ธฐ๋ณธ๊ฐ๊ณผ ๊ฐ๋๋ผ๋ (๊ธฐ๋ณธ๊ฐ์์ ๊ฐ์ ธ์ค๋ ๋์ ) ๊ฐ๋ค์ด ๋ช
์์ ์ผ๋ก ์ค์ ๋์๋ค๋ ๊ฒ์ ์ธ์งํ ์ ๋๋ก FastAPI๋ ์ถฉ๋ถํ ๋๋ํฉ๋๋ค(์ฌ์ค, Pydantic์ด ์ถฉ๋ถํ ๋๋ํฉ๋๋ค).
๋ฐ๋ผ์ JSON ์คํค๋ง์ ํฌํจ๋ฉ๋๋ค.
ํ
None
๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ์ด๋ค ๊ฒ๋ ๊ธฐ๋ณธ๊ฐ์ด ๋ ์ ์์ต๋๋ค.
๋ฆฌ์คํธ([]
), float
์ธ 10.5
๋ฑ์ด ๋ ์ ์์ต๋๋ค.
response_model_include
๋ฐ response_model_exclude
¶
๊ฒฝ๋ก ๋์ ๋ฐ์ฝ๋ ์ดํฐ ๋งค๊ฐ๋ณ์ response_model_include
๋ฐ response_model_exclude
๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๋ค์ ํฌํจ(๋๋จธ์ง ์๋ต)ํ๊ฑฐ๋ ์ ์ธ(๋๋จธ์ง ํฌํจ) ํ ์ดํธ๋ฆฌ๋ทฐํธ์ ์ด๋ฆ๊ณผ str
์ set
์ ๋ฐ์ต๋๋ค.
Pydantic ๋ชจ๋ธ์ด ํ๋๋ง ์๊ณ ์ถ๋ ฅ์์ โโ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๋ ค๋ ๊ฒฝ์ฐ ๋น ๋ฅธ ์ง๋ฆ๊ธธ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ
ํ์ง๋ง ์ด๋ฌํ ๋งค๊ฐ๋ณ์ ๋์ ์ฌ๋ฌ ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ ์์ด๋์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค.
์ด๋ ์ผ๋ถ ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์๋ตํ๊ธฐ ์ํด response_model_include
๋๋ response_model_exclude
๋ฅผ ์ฌ์ฉํ๋๋ผ๋ ์ฑ์ OpenAPI(๋ฐ ๋ฌธ์)๊ฐ ์์ฑํ JSON ์คํค๋ง๊ฐ ์ฌ์ ํ ์ ์ฒด ๋ชจ๋ธ์ ๋ํ ์คํค๋ง์ด๊ธฐ ๋๋ฌธ์
๋๋ค.
๋น์ทํ๊ฒ ์๋ํ๋ response_model_by_alias
์ญ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ์ฉ๋ฉ๋๋ค.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[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]
ํ
๋ฌธ๋ฒ {"name", "description"}
์ ๋ ๊ฐ์ ๊ฐ๋ set
์ ๋ง๋ญ๋๋ค.
์ด๋ set(["name", "description"])
๊ณผ ๋์ผํฉ๋๋ค.
set
๋์ list
์ฌ์ฉํ๊ธฐ¶
list
๋๋ tuple
๋์ set
์ ์ฌ์ฉํ๋ ๋ฒ์ ์์๋๋ผ๋, FastAPI๋ set
์ผ๋ก ๋ณํํ๊ณ ์ ์์ ์ผ๋ก ์๋ํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[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]
์์ฝ¶
์๋ต ๋ชจ๋ธ์ ์ ์ํ๊ณ ๊ฐ์ธ์ ๋ณด๊ฐ ํํฐ๋๋ ๊ฒ์ ๋ณด์ฅํ๊ธฐ ์ํด ๊ฒฝ๋ก ๋์ ๋ฐ์ฝ๋ ์ดํฐ์ ๋งค๊ฐ๋ณ์ response_model
์ ์ฌ์ฉํ์ธ์.
๋ช
์์ ์ผ๋ก ์ค์ ๋ ๊ฐ๋ง ๋ฐํํ๋ ค๋ฉด response_model_exclude_unset
์ ์ฌ์ฉํ์ธ์.