FastAPI에서 Pydantic 모델 validation 커스터마이징

문제 상황

회원가입 API를 개발하면서 비밀번호 정책 검증이 필요했다. 최소 8자 이상, 대소문자/숫자/특수문자 포함 여부를 체크해야 했는데, Pydantic의 기본 validator로는 에러 메시지 커스터마이징이 제한적이었다.

validator 데코레이터 활용

from pydantic import BaseModel, validator
import re

class UserCreate(BaseModel):
    email: str
    password: str
    
    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('비밀번호는 8자 이상이어야 합니다')
        if not re.search(r'[A-Z]', v):
            raise ValueError('대문자를 포함해야 합니다')
        if not re.search(r'[a-z]', v):
            raise ValueError('소문자를 포함해야 합니다')
        if not re.search(r'[0-9]', v):
            raise ValueError('숫자를 포함해야 합니다')
        return v

root_validator로 필드 간 검증

비밀번호 확인 필드가 추가되면서 두 필드를 비교해야 하는 상황이 생겼다. root_validator를 사용하면 모든 필드에 접근할 수 있다.

from pydantic import root_validator

class UserCreate(BaseModel):
    email: str
    password: str
    password_confirm: str
    
    @root_validator
    def verify_password_match(cls, values):
        pw1 = values.get('password')
        pw2 = values.get('password_confirm')
        if pw1 != pw2:
            raise ValueError('비밀번호가 일치하지 않습니다')
        return values

정리

  • @validator: 단일 필드 검증, 값 변환에 적합
  • @root_validator: 여러 필드 간 관계 검증에 사용
  • pre=True 옵션으로 타입 변환 전 검증 가능

FastAPI + Pydantic 조합은 API 개발 속도를 확실히 높여줬다. 타입 힌팅과 자동 문서화까지 제공되니 Flask보다 생산성이 좋았다.

FastAPI에서 Pydantic 모델 validation 커스터마이징