FastAPI에서 Pydantic 모델로 요청 검증 자동화하기
배경
사내 관리자 API를 Express에서 FastAPI로 전환하는 작업을 진행했다. Node 서버가 나쁜 건 아니었지만, 데이터 파이프라인 팀과의 협업을 고려해 Python 기반으로 통일하기로 결정됐다.
기존 방식의 문제
Express에서는 요청 검증을 위해 Joi나 직접 작성한 validator를 사용했다.
app.post('/users', (req, res) => {
const { email, age } = req.body;
if (!email || !email.includes('@')) {
return res.status(400).json({ error: 'Invalid email' });
}
if (typeof age !== 'number' || age < 0) {
return res.status(400).json({ error: 'Invalid age' });
}
// 실제 로직...
});
매번 이런 검증 코드를 작성하는 게 번거로웠다.
FastAPI + Pydantic 적용
FastAPI는 Pydantic 모델을 사용해 자동으로 검증과 문서화를 처리한다.
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, validator
app = FastAPI()
class UserCreate(BaseModel):
email: EmailStr
age: int
name: str
@validator('age')
def age_must_be_positive(cls, v):
if v < 0:
raise ValueError('must be positive')
return v
@app.post("/users")
async def create_user(user: UserCreate):
# 여기 도달했다면 이미 검증 완료
return {"email": user.email, "age": user.age}
잘못된 요청이 들어오면 자동으로 422 응답과 함께 상세한 에러 메시지를 반환한다.
실제 적용 사례
중첩된 객체 검증도 깔끔하게 처리할 수 있었다.
class Address(BaseModel):
street: str
city: str
zipcode: str
class UserWithAddress(BaseModel):
email: EmailStr
address: Address
타입 힌트 덕분에 IDE 자동완성도 잘 작동했고, mypy로 정적 타입 체크까지 가능했다.
결과
- 검증 로직 코드량 약 40% 감소
- 자동 생성되는 OpenAPI 문서로 프론트엔드 팀과의 소통 개선
- 타입 안정성 확보
재택근무 중이라 팀원들과 직접 만나 설명하긴 어려웠지만, 자동 생성된 /docs 엔드포인트를 공유하니 API 스펙 전달이 훨씬 수월했다.