FastAPI와 Pydantic으로 타입 안전한 API 구축하기
배경
사내 레거시 API 서버가 Flask로 구축되어 있었는데, 요청/응답 검증 로직이 수동으로 작성되어 있어 유지보수가 어려웠다. TypeScript 프로젝트에서 타입 시스템의 이점을 경험한 터라, Python에서도 비슷한 접근을 시도해보기로 했다.
FastAPI + Pydantic 도입
FastAPI는 Pydantic 모델을 기반으로 자동으로 요청 검증과 OpenAPI 문서를 생성해준다.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, validator
from typing import Optional
app = FastAPI()
class UserCreateRequest(BaseModel):
email: str
username: str
age: Optional[int] = None
@validator('email')
def validate_email(cls, v):
if '@' not in v:
raise ValueError('유효한 이메일이 아닙니다')
return v
@app.post("/users")
async def create_user(user: UserCreateRequest):
# 이미 검증된 데이터가 들어옴
return {"message": "success", "user": user.dict()}
주요 개선 사항
1. 자동 검증
기존 Flask에서는 request.json을 일일이 체크했어야 했는데, Pydantic이 자동으로 타입과 필수 필드를 검증한다. 잘못된 요청은 422 에러와 함께 상세한 에러 메시지를 반환한다.
2. IDE 지원
Pydantic 모델 덕분에 타입 힌트가 제대로 작동해서 자동완성과 타입 체크가 가능해졌다. 이전에는 딕셔너리로 데이터를 다뤄서 오타나 키 누락 문제가 많았다.
3. 자동 문서화
/docs 엔드포인트로 접속하면 Swagger UI가 자동 생성되어 있다. API 스펙 문서를 따로 관리할 필요가 없어졌다.
마이그레이션 전략
전체를 한 번에 바꾸지 않고 새로운 엔드포인트부터 FastAPI로 작성했다. Flask와 FastAPI를 nginx에서 경로 기반으로 라우팅해서 점진적으로 전환 중이다.
성능도 개선됐다. 비동기 처리가 기본이라 I/O 바운드 작업이 많은 서비스에서 체감상 응답 속도가 빨라졌다.
결론
TypeScript의 타입 시스템을 경험해본 개발자라면 FastAPI + Pydantic 조합이 매우 익숙하게 느껴질 것이다. Python에서도 타입 안전성을 확보할 수 있다는 점이 가장 큰 수확이었다.