Python으로 빠르고 직관적인 API 서버를 만들고 싶다면, FastAPI는 최고의 선택지 중 하나이다. 이 글에서는 FastAPI의 주요 특징부터 기본 사용법, 그리고 다양한 입력 방식에 대해 예제와 함께 정리한다.
FastAPI란?
FastAPI는 Python 3.7+에서 사용할 수 있는 현대적인 웹 프레임워크로, 높은 성능과 생산성을 동시에 제공한다. Starlette(비동기 웹 프레임워크)와 Pydantic(데이터 검증 라이브러리)을 기반으로 만들어졌으며, Go나 Node.js 수준의 성능을 자랑한다.
FastAPI의 특징
- 빠름: Starlette과 Pydantic 덕분에 NodeJS, Go와 대등한 수준의 고성능을 제공한다. 가장 빠른 Python 프레임워크 중 하나이다.
- 생산성 증가: 기능 개발 속도가 200%~300%까지 빨라지고, 사람에 의한 에러 발생률은 40% 가까이 줄어든다.
- 훌륭한 편집기 지원: 타입 힌트를 활용한 자동완성과 코드 분석 기능이 뛰어나 디버깅 시간이 줄어든다.
- 간결함: 코드 중복을 줄이고, 매개변수 선언을 통해 다양한 기능을 처리할 수 있다.
- 표준 기반 설계: OpenAPI(Swagger) 및 JSON Schema를 기반으로 문서화 및 API 설계가 가능하다.
- 자동 문서화: 작성한 API는 자동으로 문서화되며,
/docs,/redoc에서 바로 확인할 수 있다.
기본 코드 예제
from typing import Union
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: Union[str, None] = None):
return {'item_id': item_id, 'q': q}
경로 매개변수
경로 매개변수는 URL 경로 일부를 변수처럼 사용할 수 있는 기능이다. 필수로 입력되어야 하며, 타입 힌트를 통해 자동 검증도 가능하다.
기본 사용 예시
@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
return {"file_path": file_path}
숫자 검증과 순서
from fastapi import FastAPI, Path, Query
from typing import Union
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: Union[str, None] = Query(default=None, alias="item-query")
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
gt,ge,lt,le등의 옵션으로 숫자 범위 검증이 가능하다.- 고정 경로보다 동적 경로가 아래에 위치해야 정상 작동한다.
쿼리 매개변수
경로 외에 URL에 포함되는 매개변수는 쿼리 매개변수라 한다. URL에서? key=value 형식으로 전달되며, &로 구분한다.
기본 예시
http://127.0.0.1:8000/items/?skip=0&limit=10
from fastapi import FastAPI, Query
from typing import Union
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):
return {"q": q}
다중 값과 리스트
from typing import List, Union
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):
return {"q": q}
모델로 받기
from typing import Annotated, Literal
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
app = FastAPI()
class FilterParams(BaseModel):
limit: int = Field(100, gt=0, le=100)
offset: int = Field(0, ge=0)
order_by: Literal["created_at", "updated_at"] = "created_at"
tags: list[str] = []
@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
return filter_query
요청 본문 (Request Body)
요청 본문은 클라이언트가 서버로 데이터를 보낼 때 사용하는 영역으로, 주로 POST, PUT 요청에서 사용된다. FastAPI는 Pydantic 모델을 활용해 JSON 데이터를 자동으로 검증하고 파싱해준다.
기본 예시
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.dict()
if item.tax:
item_dict["price_with_tax"] = item.price + item.tax
return item_dict
경로 + 쿼리 + 본문을 동시에 받기
from fastapi import FastAPI, Path
from typing import Union
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: Union[str, None] = None,
item: Union[Item, None] = None
):
result = {"item_id": item_id}
if q:
result["q"] = q
if item:
result["item"] = item
return result
중첩 모델 (Nested Models)
from typing import List, Set, Union
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: Set[str] = set()
images: Union[List[Image], None] = None
class Offer(BaseModel):
name: str
description: Union[str, None] = None
price: float
items: List[Item]
@app.post("/offers/")
async def create_offer(offer: Offer):
return offer
요청 예제 데이터 작성
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
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
]
}
}
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
return {"item_id": item_id, "item": item}
마무리
FastAPI는 빠르고 안정적인 API 서버를 구축하는 데 최적화된 프레임워크이다. 자동 문서화, 데이터 검증, 편리한 타입 선언 등 많은 장점을 제공하며, 특히 Python에 익숙한 개발자라면 빠르게 익히고 활용할 수 있다. 위 내용을 기반으로 작은 프로젝트부터 천천히 시작해 보자.