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 스펙 전달이 훨씬 수월했다.

FastAPI에서 Pydantic 모델로 요청 검증 자동화하기