FastAPI
FastAPI νλ μμν¬, κ³ μ±λ₯, κ°νΈν νμ΅, λΉ λ₯Έ μ½λ μμ±, μ€λΉλ νλ‘λμ
λ¬Έμ: https://fastapi.tiangolo.com
μμ€ μ½λ: https://github.com/tiangolo/fastapi
FastAPIλ νλμ μ΄κ³ , λΉ λ₯΄λ©°(κ³ μ±λ₯), νμ΄μ¬ νμ€ νμ ννΈμ κΈ°μ΄ν Python3.6+μ APIλ₯Ό λΉλνκΈ° μν μΉ νλ μμν¬μ λλ€.
μ£Όμ νΉμ§μΌλ‘:
-
λΉ λ¦: (Starletteκ³Ό Pydantic λλΆμ) NodeJS λ° Goμ λλ±ν μ λλ‘ λ§€μ° λμ μ±λ₯. μ¬μ© κ°λ₯ν κ°μ₯ λΉ λ₯Έ νμ΄μ¬ νλ μμν¬ μ€ νλ.
-
λΉ λ₯Έ μ½λ μμ±: μ½ 200%μμ 300%κΉμ§ κΈ°λ₯ κ°λ° μλ μ¦κ°. *
- μ μ λ²κ·Έ: μ¬λ(κ°λ°μ)μ μν μλ¬ μ½ 40% κ°μ. *
- μ§κ΄μ : νλ₯ν νΈμ§κΈ° μ§μ. λͺ¨λ κ³³μμ μλμμ±. μ μ λλ²κΉ μκ°.
- μ¬μ: μ½κ² μ¬μ©νκ³ λ°°μ°λλ‘ μ€κ³. μ μ λ¬Έμ μ½κΈ° μκ°.
- μ§§μ: μ½λ μ€λ³΅ μ΅μν. κ° λ§€κ°λ³μ μ μΈμ μ¬λ¬ κΈ°λ₯. μ μ λ²κ·Έ.
- κ²¬κ³ ν¨: μ€λΉλ νλ‘λμ μ© μ½λλ₯Ό μ»μΌμΈμ. μλ λνν λ¬Έμμ ν¨κ».
- νμ€ κΈ°λ°: APIμ λν (μμ ν νΈνλλ) κ°λ°©ν νμ€ κΈ°λ°: OpenAPI (μ΄μ μ Swaggerλ‘ μλ €μ‘λ) λ° JSON μ€ν€λ§.
* λ΄λΆ κ°λ°νμ νλ‘λμ μ ν리μΌμ΄μ μ λΉλν ν μ€νΈμ κ·Όκ±°ν μΈ‘μ
골λ μ€ν°μ¶
μ견뀶
"[...] μ λ μμ¦ FastAPIλ₯Ό λ§μ΄ μ¬μ©νκ³ μμ΅λλ€. [...] μ¬μ€ μ°λ¦¬ νμ λ§μ΄ν¬λ‘μννΈ ML μλΉμ€ μ λΆλ₯Ό λ°κΏ κ³νμ λλ€. κ·Έμ€ μΌλΆλ ν΅μ¬ Windowsμ λͺλͺμ Office μ νλ€μ΄ ν΅ν©λκ³ μμ΅λλ€."
"FastAPI λΌμ΄λΈλ¬λ¦¬λ₯Ό μ±ννμ¬ μμΈ‘μ μ»κΈ° μν΄ μΏΌλ¦¬λ₯Ό μ€ν ν μ μλ REST μλ²λ₯Ό μμ±νμ΅λλ€. [Ludwigμ μν΄]"
"Netflixλ μ°λ¦¬μ μ€ν μμ€ λ°°ν¬νμΈ μκΈ° κ΄λ¦¬ μ€μΌμ€νΈλ μ΄μ νλ μμν¬λ₯Ό λ°νν μ μμ΄ κΈ°μ©λλ€: λ°λ‘ Dispatchμ λλ€! [FastAPIλ‘ λΉλ]"
"FastAPIκ° λ무 μ’μμ κ΅¬λ¦ μλ₯Ό κ±·λλ― ν©λλ€. μ λ§ μ¦κ²μ΅λλ€!"
"μμ§ν, λΉμ μ΄ λ§λ κ²μ λ§€μ° κ²¬κ³ νκ³ μΈλ ¨λμ΄ λ³΄μ λλ€. μ¬λ¬ λ©΄μμ Hugκ° μ΄λ κ² λμμΌλ©΄ ν©λλ€ - κ·Έκ±Έ λ§λ λκ΅°κ°λ₯Ό 보λ κ²μ λ§μ μκ°μ μ€λλ€."
"REST APIλ₯Ό λ§λ€κΈ° μν΄ νλμ μΈ νλ μμν¬λ₯Ό μ°Ύκ³ μλ€λ©΄ FastAPIλ₯Ό νμΈν΄ 보μΈμ. [...] λΉ λ₯΄κ³ , μ°κΈ° μ½κ³ , λ°°μ°κΈ°λ μ½μ΅λλ€ [...]"
"μ°λ¦¬ APIλ₯Ό FastAPIλ‘ λ°κΏ¨μ΅λλ€ [...] μλ§ μ¬λ¬λΆλ μ’μνμ€ κ²λλ€ [...]"
Typer, FastAPIμ CLI¶
μΉ API λμ ν°λ―Έλμμ μ¬μ©ν CLI μ±μ λ§λ€κ³ μλ€λ©΄, Typerλ₯Ό νμΈν΄ 보μΈμ.
Typerλ FastAPIμ λμμ λλ€. κ·Έλ¦¬κ³ FastAPIμ CLIκ° λκΈ° μν΄ μκ²Όμ΅λλ€. β¨οΈ π
μꡬμ¬ν¶
Python 3.6+
FastAPIλ κ±°μΈλ€μ μ΄κΉ¨ μμ μ μμ΅λλ€:
μ€μΉ¶
$ pip install fastapi
---> 100%
νλ‘λμ μ μν΄ Uvicorn λλ Hypercornκ³Ό κ°μ ASGI μλ²λ νμν κ²λλ€.
$ pip install uvicorn[standard]
---> 100%
μμ ¶
λ§λ€κΈ°¶
main.py
νμΌμ λ§λμΈμ:
from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
λλ
async def
μ¬μ©νκΈ°...
μ¬λ¬λΆμ μ½λκ° async
/ await
μ μ¬μ©νλ€λ©΄, async def
λ₯Ό μ¬μ©νμΈμ:
from typing import Optional
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
Note:
μ λͺ¨λ₯΄κ² λ€λ©΄, λ¬Έμμμ async
μ await
μ κ΄ν "κΈνμΈμ?" μΉμ
μ νμΈν΄ 보μΈμ.
μ€ννκΈ°¶
μλ²λ₯Ό μ€ννμΈμ:
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
uvicorn main:app --reload
λͺ
λ Ήμ κ΄νμ¬...
λͺ
λ Ή uvicorn main:app
μ λ€μμ λνλ
λλ€:
main
:main.py
νμΌ (νμ΄μ¬ "λͺ¨λ").app
: the object created inside ofmain.py
with the lineapp = FastAPI()
.--reload
: μ½λκ° λ³κ²½λ ν μλ² μ¬μμνκΈ°. κ°λ°νκ²½μμλ§ μ¬μ©νμΈμ.
νμΈνκΈ°¶
λΈλΌμ°μ λ‘ http://127.0.0.1:8000/items/5?q=somequeryλ₯Ό μ΄μ΄λ³΄μΈμ.
μλμ JSON μλ΅μ λ³Ό μ μμ΅λλ€:
{"item_id": 5, "q": "somequery"}
μ¬λ¬λΆμ λ²μ¨ APIλ₯Ό λ§λ€μμ΅λλ€:
- κ²½λ‘
/
λ°/items/{item_id}
μμ HTTP μμ² λ°κΈ°. - λ κ²½λ‘ λͺ¨λ
GET
μ°μ°(HTTP λ©μλ λ‘ μλ €μ§)μ λ°μ΅λλ€. - κ²½λ‘
/items/{item_id}
λ κ²½λ‘ λ§€κ°λ³μint
ν μ΄μ΄μΌ νλitem_id
λ₯Ό κ°μ§κ³ μμ΅λλ€. - κ²½λ‘
/items/{item_id}
λ μ νμ μΈstr
ν μ΄μ΄μΌ νλ κ²½λ‘ λ§€κ°λ³μq
λ₯Ό κ°μ§κ³ μμ΅λλ€.
λνν API λ¬Έμ¶
μ΄μ http://127.0.0.1:8000/docsλ‘ κ°λ³΄μΈμ.
μλ λνν API λ¬Έμλ₯Ό λ³Ό μ μμ΅λλ€ (Swagger UI μ 곡):
λμ API λ¬Έμ¶
κ·Έλ¦¬κ³ μ΄μ http://127.0.0.1:8000/redocλ‘ κ°λ³΄μΈμ.
λ€λ₯Έ μλ λ¬Έμλ₯Ό λ³Ό μ μμ΅λλ€(ReDoc μ 곡):
μμ κ°μ ¶
μ΄μ PUT
μμ²μ μλ λ³Έλ¬Έ(Body)μ λ°κΈ° μν΄ main.py
λ₯Ό μμ ν΄λ΄
μλ€.
Pydanticμ μ΄μ©ν΄ νμ΄μ¬ νμ€ νμ μΌλ‘ λ³Έλ¬Έμ μ μΈν©λλ€.
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
μλ²κ° μλμΌλ‘ 리λ‘λ© ν μ μμ΄μΌ ν©λλ€ (μμμ uvicorn
λͺ
λ Ήμ --reload
μ μΆκ° νκΈ° λλ¬Έμ
λλ€).
λνν API λ¬Έμ μ κ·Έλ μ΄λ¶
μ΄μ http://127.0.0.1:8000/docsλ‘ μ΄λν©λλ€.
- λνν API λ¬Έμκ° μ λ³Έλ¬Έκ³Ό ν¨κ» μλμΌλ‘ μ λ°μ΄νΈ ν©λλ€:
- "Try it out" λ²νΌμ ν΄λ¦νλ©΄, λ§€κ°λ³μλ₯Ό μ±μΈ μ μκ² ν΄μ£Όκ³ μ§μ APIμ μνΈμμ© ν μ μμ΅λλ€:
- κ·Έλ¬κ³ λμ "Execute" λ²νΌμ λλ₯΄λ©΄, μ¬μ©μ μΈν°νμ΄μ€λ APIμ ν΅μ νκ³ λ§€κ°λ³μλ₯Ό μ μ‘νλ©° κ·Έ κ²°κ³Όλ₯Ό κ°μ Έμμ νλ©΄μ νμν©λλ€:
λμ API λ¬Έμ μ κ·Έλ μ΄λ¶
κ·Έλ¦¬κ³ μ΄μ , http://127.0.0.1:8000/redocλ‘ μ΄λν©λλ€.
- λμ λ¬Έμ μμ μ 쿼리 λ§€κ°λ³μμ λ³Έλ¬Έμ λ°μν©λλ€:
μμ½¶
μμ½νλ©΄, μ¬λ¬λΆμ λ§€κ°λ³μμ νμ , λ³Έλ¬Έ λ±μ ν¨μ λ§€κ°λ³μλ‘μ¨ νλ²μ μ μΈνμ΅λλ€.
μ¬λ¬λΆμ νλ νμ€ νμ΄μ¬ νμ μΌλ‘ μ΄λ₯Ό ννμ΅λλ€.
μλ‘μ΄ λ¬Έλ², νΉμ λΌμ΄λΈλ¬λ¦¬μ λ©μλλ ν΄λμ€ λ±μ λ°°μΈ νμκ° μμ΅λλ€.
κ·Έμ νμ€ Python 3.6+μ λλ€.
μλ₯Ό λ€μ΄, int
μ λν΄μ :
item_id: int
λλ μ’ λ 볡μ‘ν Item
λͺ¨λΈμ λν΄μ :
item: Item
...κ·Έλ¦¬κ³ λ¨ νλμ μ μΈμΌλ‘ μ¬λ¬λΆμ΄ μ»λ κ²μ:
- λ€μμ ν¬ν¨ν νΈμ§κΈ° μ§μ:
- μλμμ±.
- νμ κ²μ¬.
- λ°μ΄ν° κ²μ¦:
- λ°μ΄ν°κ° μ ν¨νμ§ μμ λ μλμΌλ‘ μμ±νλ λͺ νν μλ¬.
- μ€μ²©λ JSON κ°μ²΄μ λν μ ν¨μ± κ²μ¬.
- μ
λ ₯ λ°μ΄ν° λ³ν: λ€νΈμν¬μμ νμ΄μ¬ λ°μ΄ν° λ° νμ
μΌλ‘ μ μ‘. μ½μ μ μλ κ²λ€:
- JSON.
- κ²½λ‘ λ§€κ°λ³μ.
- 쿼리 λ§€κ°λ³μ.
- μΏ ν€.
- ν€λ.
- νΌ(Forms).
- νμΌ.
- μΆλ ₯ λ°μ΄ν° λ³ν: νμ΄μ¬ λ°μ΄ν° λ° νμ
μ λ€νΈμν¬ λ°μ΄ν°λ‘ μ ν(JSON νμμΌλ‘):
- νμ΄μ¬ νμ
λ³ν (
str
,int
,float
,bool
,list
, λ±). datetime
κ°μ²΄.UUID
κ°μ²΄.- λ°μ΄ν°λ² μ΄μ€ λͺ¨λΈ.
- ...λ λ§μ κ²λ€.
- νμ΄μ¬ νμ
λ³ν (
- λμκ°λ₯ν μ¬μ©μ μΈν°νμ΄μ€λ₯Ό 2κ° ν¬ν¨ν μλ λνν API λ¬Έμ:
- Swagger UI.
- ReDoc.
μ΄μ μ½λ μμ λ‘ λμκ°μ, FastAPIλ λ€μμ²λΌ μ²λ¦¬ν©λλ€:
GET
λ°PUT
μμ²μitem_id
κ° κ²½λ‘μ μλμ§ κ²μ¦.GET
λ°PUT
μμ²μitem_id
κ°int
νμ μΈμ§ κ²μ¦.- κ·Έλ μ§ μλ€λ©΄ ν΄λΌμ΄μΈνΈλ μ μ©νκ³ λͺ νν μλ¬λ₯Ό λ³Ό μ μμ΅λλ€.
GET
μμ²μq
λΌλ μ νμ μΈ μΏΌλ¦¬ λ§€κ°λ³μκ° κ²μ¬(http://127.0.0.1:8000/items/foo?q=somequery
μ²λΌ).q
λ§€κ°λ³μλ= None
μΌλ‘ μ μΈλμκΈ° λλ¬Έμ μ νμ¬νμ λλ€.None
μ΄ μλ€λ©΄ νμμ¬νμ λλ€(PUT
μ κ²½μ°μ λ§μ°¬κ°μ§λ‘).
/items/{item_id}
μΌλ‘μPUT
μμ²μ λ³Έλ¬Έμ JSONμΌλ‘ μ½μ:name
μ νμ μμ±μΌλ‘ κ°κ³str
νμΈμ§ κ²μ¬.price
μ νμ μμ±μΌλ‘ κ°κ³float
νμΈμ§ κ²μ¬.- λ§μ½ μ£Όμ΄μ§λ€λ©΄,
is_offer
λ₯Ό μ ν μμ±μΌλ‘ κ°κ³bool
νμΈμ§ κ²μ¬. - μ΄ λͺ¨λ κ²μ κΉμ΄ μ€μ²©λ JSON κ°μ²΄μλ μ μ©λ©λλ€.
- JSONμΌλ‘, κ·Έλ¦¬κ³ μμλΆν° μλ λ³ν.
- λ€μμμ μ¬μ©ν μ μλ λͺ¨λ κ²μ OpenAPIλ‘ λ¬Έμν:
- λνν λ¬Έμ μμ€ν .
- μ¬λ¬ μΈμ΄λ€μ λν μλ ν΄λΌμ΄μΈνΈ μ½λ μμ± μμ€ν .
- 2κ°μ λνν λ¬Έμ μΉ μΈν°νμ΄μ€λ₯Ό μ§μ μ 곡.
μ°λ¦¬λ κ·Έμ μλ° κ²ν‘κΈ°λ§ νμ λΏμΈλ° μ¬λ¬λΆμ λ²μ¨ μ΄λ»κ² μλνλμ§ μκ³ μμ΅λλ€.
λ€μ μ€μ λ°κΏλ³΄μΈμ:
return {"item_name": item.name, "item_id": item_id}
...μμ:
... "item_name": item.name ...
...μΌλ‘:
... "item_price": item.price ...
...κ·Έλ¬κ³ λμ μ¬λ¬λΆμ νΈμ§κΈ°κ° μμ±κ³Ό νμ μ μκ³ μλ μμ±νλμ§ λ³΄μΈμ:
λ λ§μ κΈ°λ₯μ ν¬ν¨ν λ³΄λ€ μμ ν μμ μ κ²½μ°, νν λ¦¬μΌ - μ¬μ©μ κ°μ΄λλ₯Ό 보μΈμ.
μ€ν¬μΌλ¬ μ£Όμ: νν λ¦¬μΌ - μ¬μ©μ κ°μ΄λλ:
- μλ‘ λ€λ₯Έ μ₯μμμ λ§€κ°λ³μ μ μΈ: ν€λ, μΏ ν€, νΌ νλ κ·Έλ¦¬κ³ νμΌ.
maximum_length
λλregex
μ²λΌ μ ν¨μ± μ μ½νλ λ°©λ².- κ°λ ₯νκ³ μ¬μ©νκΈ° μ¬μ΄ μμ‘΄μ± μ£Όμ μμ€ν .
- OAuth2 μ§μμ ν¬ν¨ν JWT tokens λ° HTTP Basicμ κ°λ 보μκ³Ό μΈμ¦.
- (Pydantic λλΆμ) κΉμ μ€μ²© JSON λͺ¨λΈμ μ μΈνλλ° λ μ§λ³΄ν (νμ§λ§ λ§μ°¬κ°μ§λ‘ μ¬μ΄) κΈ°μ .
- (Starlette λλΆμ) λ§μ μΆκ° κΈ°λ₯:
- μΉ μμΌ
- GraphQL
requests
λ°pytest
μ κΈ°λ°ν κ·Ήν μ¬μ΄ ν μ€νΈ- CORS
- μΏ ν€ μΈμ
- ...κΈ°ν λ±λ±.
μ±λ₯¶
λ 립λ TechEmpower λ²€μΉλ§ν¬μμ Uvicornμμ μλνλ FastAPI μ΄ν리μΌμ΄μ μ΄ μ¬μ© κ°λ₯ν κ°μ₯ λΉ λ₯Έ νλ μμν¬ μ€ νλλ‘ Starletteμ Uvicorn(FastAPIμμ λ΄λΆμ μΌλ‘ μ¬μ©)μλ§ λ°λκ³ μμ΅λλ€. (*)
μμΈν λ΄μ©μ λ²€μΉλ§ν¬ μΉμ μ 보μΈμ.
μ νκ°λ₯ν μ’ μμ¬ν¶
Pydanticμ΄ μ¬μ©νλ:
ujson
- λ λΉ λ₯Έ JSON "νμ±".email_validator
- μ΄λ©μΌ μ ν¨μ± κ²μ¬.
Starletteμ΄ μ¬μ©νλ:
requests
-TestClient
λ₯Ό μ¬μ©νλ €λ©΄ νμ.aiofiles
-FileResponse
λλStaticFiles
λ₯Ό μ¬μ©νλ €λ©΄ νμ.jinja2
- κΈ°λ³Έ ν νλ¦Ώ μ€μ μ μ¬μ©νλ €λ©΄ νμ.python-multipart
-request.form()
κ³Ό ν¨κ» "parsing"μ μ§μμ μνλ©΄ νμ.itsdangerous
-SessionMiddleware
μ§μμ μν΄ νμ.pyyaml
- StarletteμSchemaGenerator
μ§μμ μν΄ νμ (FastAPIμ μΈλλ νμκ° μμ κ²λλ€).graphene
-GraphQLApp
μ§μμ μν΄ νμ.ujson
-UJSONResponse
λ₯Ό μ¬μ©νλ €λ©΄ νμ.
FastAPI / Starletteμ΄ μ¬μ©νλ:
uvicorn
- μ ν리μΌμ΄μ μ λ‘λνκ³ μ 곡νλ μλ².orjson
-ORJSONResponse
μ μ¬μ©νλ €λ©΄ νμ.
pip install fastapi[all]
λ₯Ό ν΅ν΄ μ΄ λͺ¨λλ₯Ό μ€μΉ ν μ μμ΅λλ€.
λΌμ΄μΌμ€¶
μ΄ νλ‘μ νΈλ MIT λΌμ΄μΌμ€ μ‘°μ½μ λ°λΌ λΌμ΄μΌμ€κ° λΆμ¬λ©λλ€.