์์ฒญ ๋ณธ๋ฌธ¶
ํด๋ผ์ด์ธํธ(๋ธ๋ผ์ฐ์ ๋ผ๊ณ ํฉ์๋ค)์์ API๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ผ ํ ๋, ์์ฒญ ๋ณธ๋ฌธ์ ๋ณด๋ ๋๋ค.
์์ฒญ ๋ณธ๋ฌธ์ ํด๋ผ์ด์ธํธ์์ API๋ก ๋ณด๋ด๋ ๋ฐ์ดํฐ์ ๋๋ค. ์๋ต ๋ณธ๋ฌธ์ API์์ ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ด๋ ๋ฐ์ดํฐ์ ๋๋ค.
API๋ ๋๋ถ๋ถ ์๋ต ๋ณธ๋ฌธ์ ๋ณด๋ ๋๋ค. ํ์ง๋ง ํด๋ผ์ด์ธํธ๋ ํญ์ ์์ฒญ ๋ณธ๋ฌธ์ ๋ณด๋ผ ํ์๋ ์์ต๋๋ค.
์์ฒญ ๋ณธ๋ฌธ์ ์ ์ธํ๋ ค๋ฉด, ๊ฐ๋ ฅํ ํ๊ณผ ์ฅ์ ์ ๊ฐ์ง Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์ ๋ณด
๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๊ธฐ ์ํด์ ๋ค์ ์ค ํ๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค: POST
(์ข ๋ ์ผ๋ฐ์ ), PUT
, DELETE
๋๋ PATCH
.
GET
์์ฒญ์ผ๋ก ๋ณธ๋ฌธ์ ๋ณด๋ด๋ ๊ฒ์ ์ฌ์์ ์ ์๋์ง ์์ ๋์์ด ์์ง๋ง, ๊ทธ๋ผ์๋ FastAPI๋ ๋งค์ฐ ๋ณต์ก/๊ทน๋จ์ ์ฌ์ฉ ์ฌ๋ก์ ๋ํด์๋ง ์ง์๋ฉ๋๋ค.
์ด๊ฒ์ ๊ถ์ฅ๋์ง ์๊ธฐ ๋๋ฌธ์ Swagger UI ๋ํํ ๋ฌธ์๋ GET
์ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ณธ๋ฌธ์ ๋ํ ๋ฌธ์๋ฅผ ๋ณด์ฌ์ฃผ์ง ์๊ณ , ์ค๊ฐ์ ์๋ ํ๋ก์๊ฐ ์ง์ํ์ง ์์์ ์์ต๋๋ค.
Pydantic์ BaseModel
์ํฌํธ¶
์ฐ์ , pydantic
์์ BaseModel
๋ฅผ ์ํฌํธํด์ผ ํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
๋ฐ์ดํฐ ๋ชจ๋ธ ์์ฑ¶
์ด์ BaseModel
์ ์์ํ๋ ํด๋์ค๋ก ๋ฐ์ดํฐ ๋ชจ๋ธ์ ์ ์ธํฉ๋๋ค.
๋ชจ๋ ์ดํธ๋ฆฌ๋ทฐํธ์ ํ์ค ํ์ด์ฌ ํ์ ์ ์ฌ์ฉํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์๋ฅผ ์ ์ธํ ๋์ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋ชจ๋ธ ์ดํธ๋ฆฌ๋ทฐํธ์ ๊ธฐ๋ณธ๊ฐ์ด ์์ผ๋ฉด ํ์๊ฐ ์๋๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ํ์์
๋๋ค. ์ ํ์ ์ผ๋ก ๋ง๋ค๋ ค๋ฉด None
์ ์ฌ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์์์ ์ด ๋ชจ๋ธ์ JSON "object
"(๋๋ ํ์ด์ฌ dict
)๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ ์ธํฉ๋๋ค:
{
"name": "Foo",
"description": "An optional description",
"price": 45.2,
"tax": 3.5
}
...description
๊ณผ tax
๋ (None
๊ฐ์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ํ๋ฉด์) ์ ํ์ ์ด๋ฉฐ, ์ด JSON "object
" ๋ํ ์ ํจํฉ๋๋ค:
{
"name": "Foo",
"price": 45.2
}
๋งค๊ฐ๋ณ์๋ก ์ ์ธ¶
์ด๋ฅผ ๊ฒฝ๋ก ๋์์ ์ถ๊ฐํ๋ ค๋ฉด ๊ฒฝ๋ก ๋ฐ ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์๋ฅผ ์ ์ธํ ๊ฒ๊ณผ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ ์ธํฉ๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
...๊ทธ๋ฆฌ๊ณ ์์ฑํ Item
๋ชจ๋ธ๋ก ํ์
์ ์ ์ธํฉ๋๋ค.
๊ฒฐ๊ณผ¶
ํ์ด์ ํ์ ์ ์ธ๋ง์ผ๋ก FastAPI๋:
- ์์ฒญ ๋ณธ๋ฌธ์ JSON์ผ๋ก ์ฝ์ต๋๋ค.
- (ํ์ํ๋ค๋ฉด) ํด๋น ํ์ ์ ๋ณํํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฆํฉ๋๋ค.
- ๋ฐ์ดํฐ๊ฐ ์ ํจํ์ง ์๋ค๋ฉด, ์๋ชป๋ ๋ฐ์ดํฐ๊ฐ ์ด๋์์ ๋ฌด์์ธ์ง ์ ํํ๊ฒ ํ์ํ๋ ๋ฉ์ง๊ณ ๋ช ํํ ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค.
- ๋งค๊ฐ๋ณ์
item
์ ์์ ํ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํฉ๋๋ค.- ํจ์์
Item
ํ์ ์ผ๋ก ์ ์ธํจ์ผ๋ก์จ, ๋ชจ๋ ์ดํธ๋ฆฌ๋ทฐํธ์ ๊ทธ ํ์ ์ ๋ํ ํธ์ง๊ธฐ ์ง์(์๋์์ฑ ๋ฑ) ์ญ์ ์ ๊ณตํฉ๋๋ค.
- ํจ์์
- ๋ชจ๋ธ์ JSON ์คํค๋ง ์ ์๋ฅผ ์์ฑํ๊ณ , ํ๋ก์ ํธ์ ์ ํฉํ ๊ฒฝ์ฐ ์ํ๋ ๊ณณ ์ด๋์์๋ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
- ์ด ์คํค๋ง๋ค์ ์์ฑํ OpenAPI ์คํค๋ง์ ์ผ๋ถ๊ฐ ๋๋ฉฐ ์๋ UI ๋ฌธ์ํ์ ์ฌ์ฉ๋ฉ๋๋ค.
์๋ ๋ฌธ์¶
๋ชจ๋ธ์ JSON ์คํค๋ง๋ OpenAPI ์์ฑ ์คํค๋ง์ ์ผ๋ถ๊ฐ ๋๋ฉฐ ๋ํํ API ๋ฌธ์์ ํ์๋ฉ๋๋ค:
๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ ํ์๋ก ํ๋ ๊ฐ ๊ฒฝ๋ก ๋์ ๋ด์ API ๋ฌธ์์์๋ ์ฌ์ฉ๋ฉ๋๋ค:
ํธ์ง๊ธฐ ์ง์¶
ํธ์ง๊ธฐ์์ ํจ์ ๋ด๋ถ ๋ชจ๋ ๊ณณ(Pydantic ๋ชจ๋ธ ๋์ dict
๋ฅผ ๋ฐ์ ๊ฒฝ์ฐ์๋ ๋ฐ์ํ์ง ์์ต๋๋ค)์์ ํ์
ํํธ์ ์๋์์ฑ์ ์ป์ ์ ์์ต๋๋ค:
์๋ชป๋ ํ์ ์์ ์ ๋ํ ์ค๋ฅ ๊ฒ์ฌ๋ ๋ฐ์ต๋๋ค:
์ด๋ ์ฐ์ฐ์ด ์๋๋ฉฐ, ์ ์ฒด ํ๋ ์์ํฌ๋ ์ด๋ฌํ ์ค๊ณ๋ฅผ ์ค์ฌ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ตฌํํ๊ธฐ ์ ์ ์ค๊ณ ๋จ๊ณ์์ ์ฒ ์ ํ ํ ์คํธํ์ฌ ๋ชจ๋ ํธ์ง์์ ํจ๊ป ์๋ํ๋์ง ํ์ธํ์ต๋๋ค.
์ด๋ฅผ ์ง์ํ๊ธฐ ์ํด Pydantic ์์ฒด์๋ ์ฝ๊ฐ์ ๋ณ๊ฒฝ์ด ์์์ต๋๋ค.
์ด์ ์คํฌ๋ฆฐ์ท์ ๋น์ฃผ์ผ ์คํ๋์ค ์ฝ๋์์ ์ฐ์ ๊ฒ์ ๋๋ค.
ํ์ง๋ง PyCharm ๋ฐ ๋๋ถ๋ถ์ ๋ค๋ฅธ ํ์ด์ฌ ํธ์ง๊ธฐ์์ ๋์ผํ ํธ์ง๊ธฐ ์ง์์ ์ป์ ์ ์์ต๋๋ค:
ํ
PyCharm์ ํธ์ง๊ธฐ๋ก ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, Pydantic PyCharm ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ค์์ ํตํด Pydantic ๋ชจ๋ธ์ ๋ํ ํธ์ง๊ธฐ ์ง์์ ๊ฐ์ ํฉ๋๋ค:
- ์๋์์ฑ
- ํ์ ๊ฒ์ฌ
- ๋ฆฌํฉํ ๋ง
- ๊ฒ์
- ๊ฒ์ฌ(Inspection)
๋ชจ๋ธ ์ฌ์ฉ¶
ํจ์ ๋ด๋ถ์์ ๋ชจ๋ธ ๊ฐ์ฒด์ ๋ชจ๋ ์ดํธ๋ฆฌ๋ทฐํธ์ ์ง์ ์ ๊ทผํ ์ ์์ต๋๋ค:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
์์ฒญ ๋ณธ๋ฌธ + ๊ฒฝ๋ก ๋งค๊ฐ๋ณ์¶
๊ฒฝ๋ก ๋งค๊ฐ๋ณ์์ ์์ฒญ ๋ณธ๋ฌธ์ ๋์์ ์ ์ธํ ์ ์์ต๋๋ค.
FastAPI๋ ๊ฒฝ๋ก ๋งค๊ฐ๋ณ์์ ์ผ์นํ๋ ํจ์ ๋งค๊ฐ๋ณ์๋ ๊ฒฝ๋ก์์ ๊ฐ์ ธ์์ผ ํจ์, Pydantic ๋ชจ๋ธ๋ก ์ ์ธํ ํจ์ ๋งค๊ฐ๋ณ์๋ ์์ฒญ ๋ณธ๋ฌธ์์ ๊ฐ์ ธ์์ผ ํจ์ ์ธ์งํฉ๋๋ค.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item):
return {"item_id": item_id, **item.dict()}
์์ฒญ ๋ณธ๋ฌธ + ๊ฒฝ๋ก + ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์¶
๋ณธ๋ฌธ, ๊ฒฝ๋ก ๊ทธ๋ฆฌ๊ณ ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์ ์ ๋ถ๋ฅผ ๋์์ ์ ์ธํ ์๋ ์์ต๋๋ค.
FastAPI๋ ๊ฐ๊ฐ์ ์ธ์ํ๊ณ ์ฌ๋ฐ๋ฅธ ์์น์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: Union[str, None] = None):
result = {"item_id": item_id, **item.dict()}
if q:
result.update({"q": q})
return result
ํจ์ ๋งค๊ฐ๋ณ์๋ ๋ค์์ผ๋ก ์ธ์๋ฉ๋๋ค:
- ๋งค๊ฐ๋ณ์๊ฐ ๊ฒฝ๋ก์๋ ์ ์ธ๋์๋ค๋ฉด ๊ฒฝ๋ก ๋งค๊ฐ๋ณ์๋ก ์ฌ์ฉ๋ฉ๋๋ค.
- ๋งค๊ฐ๋ณ์๊ฐ ๋จ์ํ(
int
,float
,str
,bool
๋ฑ)์ด๋ฉด ์ฟผ๋ฆฌ ๋งค๊ฐ๋ณ์๋ก ํด์๋ฉ๋๋ค. - ๋งค๊ฐ๋ณ์๊ฐ Pydantic ๋ชจ๋ธ ํ์ ์ผ๋ก ์ ์ธ๋์๋ค๋ฉด ์์ฒญ ๋ณธ๋ฌธ์ผ๋ก ํด์๋ฉ๋๋ค.
์ฐธ๊ณ
FastAPI๋ q
๊ฐ = None
์ด๋ฏ๋ก ์ ํ์ ์ด๋ผ๋ ๊ฒ์ ์ธ์งํฉ๋๋ค.
Optional[str]
์ ์๋ Optional
์ FastAPI(FastAPI๋ str
๋ถ๋ถ๋ง ์ฌ์ฉํฉ๋๋ค)๊ฐ ์ฌ์ฉํ๋๊ฒ ์๋์ง๋ง, Optional[str]
์ ํธ์ง๊ธฐ์๊ฒ ์ฝ๋์์ ์ค๋ฅ๋ฅผ ์ฐพ์๋ผ ์ ์๊ฒ ๋์์ค๋๋ค.
Pydantic ์์ด ์ฌ์ฉํ๊ธฐ¶
Pydantic ๋ชจ๋ธ์ ์ฌ์ฉํ๊ณ ์ถ์ง ์๋ค๋ฉด, ๋ณธ๋ฌธ(Body) ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ณธ๋ฌธ - ๋ค์ค ๋งค๊ฐ๋ณ์: ๋ณธ๋ฌธ์ ๋จ์ํ ๊ฐ ๋ฌธ์๋ฅผ ๋ณด์ธ์.