반응형

파이썬 FastAPI Pydantic을 통한 데이터 모델링과 검증

FastAPI의 진짜 힘은 바로 Pydantic에 있다!
데이터를 자동으로 검증하고, 문서화까지 완벽하게 해주는
이 강력한 조합을 여러분은 알고 계셨나요?

 

 

안녕하세요, 여러분!

이번 글에서는 FastAPI에서 가장 자주 사용되는 기능 중 하나인 Pydantic 기반의 데이터 모델링과 검증에 대해 알아보려 합니다.

FastAPI를 처음 접할 땐 간단한 라우팅으로 시작하지만, 실제 프로젝트로 들어가면 사용자 입력 데이터의 유효성을 검증하고 그에 맞는 응답 모델을 처리하는 것이 핵심이 됩니다.

이 모든 과정을 도와주는 것이 바로 Pydantic이죠. 특히 초보 개발자들에게는 서버로 들어오는 요청이 어떤 구조인지, 그 구조가 올바른지 자동으로 확인해주는 기능은 정말 고마운 존재예요.

예외 처리, 직렬화, 문서 자동화까지 한 번에 해결할 수 있으니, 놓칠 수 없겠죠?

 

1. Pydantic BaseModel 소개와 특징 ✨

FastAPI의 진짜 매력은 어디에 있을까요? 바로 Pydantic을 활용한 자동 데이터 검증 기능에 있습니다.

Python에서 데이터 모델을 정의할 때 많은 분들이 dataclass를 사용해봤을 텐데요, Pydantic은 거기에 한 단계 더 나아가 유효성 검사, 직렬화/역직렬화, 문서화까지 제공해주는 놀라운 도구입니다.

📌 BaseModel이란?

Pydantic의 핵심은 BaseModel입니다.

BaseModel을 상속한 클래스는 구조화된 데이터 모델로서 동작하며, 입력값의 타입을 검증하고, 오류가 있으면 상세한 메시지를 반환합니다.

 

예를 들어, 사용자의 정보를 받는 모델을 아래처럼 정의할 수 있습니다.

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str
    is_active: bool = True
  • id: 정수형으로 강제
  • name: 문자열로 강제
  • is_active: 기본값 True로 설정

이 모델에 잘못된 타입이 들어오면 어떻게 될까요?

예를 들어 User(id="abc", name=123, is_active="yes")처럼 잘못된 데이터를 전달하면,

FastAPI는 422 Unprocessable Entity 오류와 함께 자세한 오류 메시지를 응답합니다.

📈 Pydantic의 장점 요약

기능 설명
타입 검증 정의된 필드 타입과 일치하지 않으면 자동으로 오류 반환
기본값 지정 필드를 선택적으로 선언 가능
입출력 직렬화 딕셔너리 ↔︎ 모델 객체 변환을 자동 처리
문서 자동화 FastAPI와 함께 사용할 경우 Swagger UI에 자동 반영

결론적으로,

Pydantic을 이용하면 데이터 구조 정의와 검증을 한 번에 처리할 수 있어 코드가 깔끔하고 안정적입니다.

초보자부터 숙련 개발자까지 모두에게 사랑받는 이유죠.

 

 

2. 데이터 유효성 검증과 오류 처리 🛡️

FastAPI에서 데이터 유효성 검증은 거의 자동으로 이뤄집니다.

Pydantic 모델을 엔드포인트 함수의 인자로 선언만 하면,

JSON 요청 바디를 파싱 → 타입 검증 → 오류 응답까지 단 한 줄의 추가 코드 없이 처리해주죠.

📥 요청 데이터 검증 흐름

  1. 클라이언트가 JSON 데이터를 POST로 전송
  2. FastAPI가 Pydantic 모델로 데이터 파싱 시도
  3. 정의된 필드 타입과 다르면 422 오류 발생
  4. 정상 파싱되면 뷰 함수에 모델 인스턴스를 넘겨줌

예를 들어, 사용자 이름을 문자열로 받아야 한다고 가정해봅시다.

그런데 클라이언트가 name: 1234처럼 숫자를 보내면?

{
  "detail": [
    {
      "loc": ["body", "name"],
      "msg": "str type expected",
      "type": "type_error.str"
    }
  ]
}

이처럼 RequestValidationError가 발생하고, FastAPI는 상세한 오류 메시지를 JSON으로 반환합니다.

개발자는 try-catch도 안 써도 되고, 클라이언트는 어떤 필드가 잘못됐는지 명확히 알 수 있죠.

⚙️ Field()를 통한 추가 제약 설정

Pydantic의 Field() 함수를 사용하면,

단순 타입 검증 외에도 문자 길이 제한, 정규표현식 검사, 기본값 설정, 예시 값 등을 지정할 수 있어요.

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=50, example="홍길동")
    email: str = Field(..., regex=r'^\S+@\S+\.\S+$', example="user@example.com")
  • min_length, max_length: 문자열 길이 제약
  • regex: 정규표현식으로 포맷 검증
  • example: Swagger 문서에 예시로 표시

이렇게 Field를 적극 활용하면 API 입력 조건이 문서화와 동시에 자동 검증되어, 사용자와 개발자 모두에게 큰 도움이 됩니다.

✅ 요약: 검증이 자동이라 행복해요

  • FastAPI + Pydantic은 요청을 자동으로 검증하고 오류를 처리한다.
  • 별도의 try-except 없이도 잘못된 요청을 막을 수 있다.
  • Field()로 더욱 정밀한 제약 조건을 줄 수 있다.

이제 우리는 Pydantic이 단순한 타입 검사 도구가 아니라 API의 품질과 신뢰도를 끌어올려주는 핵심 기술이라는 걸 확실히 알게 되었죠!

 

 

3. 요청 바디 모델링 방법 📦

FastAPI에서는 클라이언트로부터 JSON 형식의 데이터를 받을 때 Pydantic 모델을 직접 함수 매개변수에 선언하는 방식으로 간단하게 요청 바디를 처리할 수 있습니다.

이 방식은 특히 입력값이 여러 필드로 구성된 복합 구조일 때 더욱 유용하게 쓰이죠.

📝 모델 정의와 요청 처리 예제

예를 들어 할 일(Todo)을 등록하는 API를 만든다고 해봅시다.

titledescription을 갖는 요청 바디를 받아야 한다면 아래와 같이 모델을 정의할 수 있어요.

from pydantic import BaseModel

class TodoItemCreate(BaseModel):
    title: str
    description: str | None = None  # 선택적 필드

이제 위 모델을 FastAPI 라우터 함수에 인자로 넣으면 됩니다.

FastAPI는 클라이언트의 JSON 요청을 자동으로 파싱하고 item 객체로 만들어줍니다.

@app.post("/todos", status_code=201)
def create_todo(item: TodoItemCreate):
    todo = {"id": len(todos) + 1, "title": item.title, "desc": item.description}
    todos.append(todo)
    return todo

📌 요청 실패 시 자동 오류 처리

만약 클라이언트가 필수 필드인 title을 빠뜨리거나 문자열 대신 숫자를 보낸다면, 함수는 아예 실행되지 않고 FastAPI가 422 Unprocessable Entity 오류를 자동으로 반환합니다.

덕분에 우리는 로직에만 집중할 수 있고, 예외 처리 코드는 거의 필요 없습니다.

🧾 Swagger 문서 자동 반영

놀랍게도, 위처럼 Pydantic 모델을 선언하면 /docs 경로에서 자동 생성되는 Swagger UI 문서에도 입력 필드, 설명, 데이터 타입, 예시 값까지 모두 자동으로 표시됩니다.

즉, 코드를 짜는 것만으로 문서까지 완성되는 셈이죠.

🧠 요청 바디 처리 시 체크포인트

  • BaseModel을 상속한 요청 모델을 선언하자
  • 요청 본문으로 JSON 데이터가 들어오면 FastAPI가 자동으로 Pydantic 모델로 변환한다
  • 모델에 정의된 조건을 만족하지 않으면 함수가 실행되지 않고 오류를 반환한다
  • Field()를 이용해 제약조건과 문서 예시를 추가할 수 있다

이처럼 요청 바디에 Pydantic 모델을 사용하면 코드가 훨씬 직관적이고 안전합니다.

특히 프론트엔드와 협업할 때 Swagger 문서 덕분에 API 스펙 공유가 정말 쉬워집니다.

 

 

4. 응답 모델 지정과 데이터 직렬화 📤

FastAPI에서는 요청을 받을 때뿐만 아니라 응답을 보낼 때도 Pydantic 모델을 활용할 수 있습니다. response_model 파라미터를 사용하면 반환할 데이터의 구조를 명확히 지정할 수 있어요.

이를 통해 보안성, 신뢰성, 문서화까지 한 번에 해결됩니다.

📦 response_model의 기본 개념

API 엔드포인트에서 반환할 데이터가 어떤 구조여야 하는지를 response_model에 정의해두면,

FastAPI는 자동으로 해당 구조로 직렬화(serialization)하고 그 외의 필드는 제외합니다.

예를 들어,

다음과 같은 모델이 있다고 해볼게요.

class TodoItem(BaseModel):
    id: int
    title: str
    description: str | None = None

이제 GET 요청에 대해 이 모델을 응답 모델로 지정하면 다음과 같은 라우팅 코드를 작성할 수 있어요.

@app.get("/todos/{id}", response_model=TodoItem)
def read_todo(id: int):
    todo = get_todo_by_id(id)
    if not todo:
        raise HTTPException(status_code=404, detail="Todo not found")
    return todo

여기서 todo가 dict든 ORM 객체든 상관없이 FastAPI는 TodoItem 모델 형태로 자동 변환해 응답해줍니다.

내부적으로는 dict로 변환 후 JSON으로 직렬화됩니다.

🔒 보안성을 위한 필드 필터링

예를 들어 사용자 정보를 반환할 때 DB에는 hashed_password 같은 민감한 정보가 있을 수 있습니다.

이때 응답 모델에 해당 필드를 포함하지 않으면, FastAPI는 자동으로 해당 필드를 제거하고 안전한 응답만 반환합니다.

🧩 ORM 객체 대응을 위한 orm_mode

SQLAlchemy 같은 ORM을 사용할 경우, 모델 인스턴스를 바로 반환할 수 있는데요.

이때는 응답 모델 내부에 Config 클래스를 선언해 orm_mode = True로 설정해줘야 합니다.

class TodoItem(BaseModel):
    id: int
    title: str
    description: str | None = None

    class Config:
        orm_mode = True

이 설정을 해주면 FastAPI는 ORM 객체에서 필드를 자동으로 추출해서 응답 모델로 직렬화해줍니다.

🧾 response_model이 주는 이점 정리

장점 설명
데이터 필터링 불필요하거나 민감한 데이터 제거
타입 강제 모델에 맞는 타입으로 자동 변환
문서 자동화 Swagger UI에 응답 구조가 반영됨
보안 향상 출력 데이터의 제어 가능

결론적으로 response_model은 응답을 명시적으로 통제할 수 있는 강력한 기능입니다.

특히 API 문서 자동화와 보안 강화 측면에서 필수로 활용해야 할 요소죠!

 

 

5. 인메모리 Todo API 실습 예제 🧪

이제까지 배운 내용을 바탕으로 간단한 Todo API 예제를 만들어보며 실습해볼 시간이에요.

데이터베이스 없이 인메모리 리스트를 사용하여 CRUD 기능을 구현해볼 거예요.

이 과정을 통해 Pydantic 모델을 어떻게 활용하고, FastAPI의 기능과 어떻게 연결되는지 확실히 체감할 수 있습니다.

🔧 모델 정의

from pydantic import BaseModel
from typing import List, Optional

class TodoItemCreate(BaseModel):
    title: str
    description: Optional[str] = None

class TodoItem(TodoItemCreate):
    id: int
    done: bool = False

TodoItemCreate는 생성 요청용, TodoItem은 응답 및 조회용으로 사용됩니다.

생성 시에는 ID와 완료 여부가 없기 때문에 모델을 상속 구조로 나누어 중복을 줄였습니다.

🚀 엔드포인트 구현

from fastapi import FastAPI, HTTPException

app = FastAPI()
todos: List[TodoItem] = []
current_id = 0

@app.post("/todos", response_model=TodoItem, status_code=201)
def create_todo(item: TodoItemCreate):
    global current_id
    current_id += 1
    todo = TodoItem(id=current_id, **item.dict())
    todos.append(todo)
    return todo

@app.get("/todos", response_model=List[TodoItem])
def list_todos():
    return todos

@app.get("/todos/{id}", response_model=TodoItem)
def get_todo(id: int):
    for todo in todos:
        if todo.id == id:
            return todo
    raise HTTPException(status_code=404, detail="Todo not found")

@app.put("/todos/{id}", response_model=TodoItem)
def update_todo(id: int, done: bool):
    for todo in todos:
        if todo.id == id:
            todo.done = done
            return todo
    raise HTTPException(status_code=404, detail="Todo not found")

@app.delete("/todos/{id}", status_code=204)
def delete_todo(id: int):
    for idx, todo in enumerate(todos):
        if todo.id == id:
            todos.pop(idx)
            return
    raise HTTPException(status_code=404, detail="Todo not found")

📋 기능 요약

HTTP 메서드 엔드포인트 설명
POST /todos 할 일 생성
GET /todos 전체 할 일 목록 조회
GET /todos/{id} 단일 할 일 조회
PUT /todos/{id} 완료 여부 수정
DELETE /todos/{id} 삭제

이처럼 Pydantic 모델을 중심으로 CRUD API를 설계하면 입력과 출력의 명세가 명확해지고,

자동 문서화 기능까지 덤으로 얻을 수 있습니다.

작은 실습이지만, API 설계의 기본을 익히기에 딱 좋은 구조입니다!

 

 

6. 실습을 통한 개념 정리 및 확장 방향 📚

지금까지 FastAPI에서 Pydantic을 활용한 데이터 모델링과 검증에 대해 배우고, 인메모리 Todo API 예제를 통해 실습까지 마쳤습니다.

단순히 동작하는 API를 만들었다는 것 이상의 의미가 있어요.

이번 학습을 통해 우리는 다음과 같은 핵심 역량을 갖추게 되었어요.

🎯 핵심 학습 내용 정리

  • Pydantic의 BaseModel을 이용해 데이터 구조를 선언하고, 타입 검증과 기본값 설정까지 깔끔하게 처리하는 법을 익혔어요.
  • 요청 바디에 Pydantic 모델을 활용해 JSON을 자동 파싱하고 오류를 422 상태 코드로 처리하는 구조를 경험했죠.
  • response_model을 통해 응답 데이터를 명확히 통제하고, 민감 정보를 자동 제거하는 실전 팁도 확인했어요.
  • Swagger 문서화에 입력/출력 모델이 자동 반영되는 과정을 통해 개발 생산성을 실감했습니다.

🔮 다음 단계: 확장 방향 제안

이제 실전 프로젝트나 포트폴리오 개발로 확장하고 싶다면, 아래 내용을 고려해보세요.

  1. SQLite 또는 PostgreSQL 연동 – 실제 DB와 연동해 Todo를 저장하고 불러오는 구조로 확장하기
  2. SQLAlchemy ORM 사용 – ORM 객체와 Pydantic 모델을 함께 사용하는 방법 학습하기
  3. JWT 인증 추가 – 사용자 인증/인가 처리로 보안을 강화하기
  4. 테스트 코드 작성pytest 등을 이용한 유닛 테스트 추가로 품질 보장

🌈 마무리하며

단순히 작동하는 코드보다 더 중요한 건, 데이터의 흐름을 안전하고 명확하게 만드는 것입니다.

Pydantic은 그 시작이자 가장 든든한 동반자예요.

앞으로 여러분의 FastAPI 프로젝트에 이 강력한 도구를 적극 활용해보세요.

 

 

마무리 ✍️

이번 글에서는 FastAPI에서 Pydantic을 활용한 데이터 모델링과 검증 방법을 처음부터 끝까지 실습 중심으로 정리해봤습니다.

처음 접할 땐 어렵게 느껴질 수 있지만, 막상 하나하나 따라 하다 보면 자동 유효성 검사, 직렬화, 문서화 등 정말 많은 일을 FastAPI가 알아서 해주는 걸 느끼게 될 거예요.

여기서 끝나지 않고, 이제는 진짜 서비스에 연결할 준비를 해보세요.

 

SQLite, PostgreSQL 같은 실제 데이터베이스 연동부터, JWT 인증 구현, SQLAlchemy ORM 적용, 서비스 배포 등 단계별로 확장할 수 있습니다.

중요한 건, 이 모든 기반에는 Pydantic 모델링이 있다는 점이에요.

혹시 오늘 처음 FastAPI를 써보신 분이라면, 분명 놀라셨을 거예요.

어떻게 이렇게 적은 코드로 API가 만들어지고, 검증까지 되는지.

앞으로는 더 다양한 프로젝트에서 Pydantic을 능숙하게 다루실 수 있을 겁니다. 👍

 

이제 여러분의 프로젝트에서 Pydantic을 자신 있게 활용해보세요.

복잡한 데이터 구조도 깔끔하게, 예외 처리도 자동으로, API 문서화까지 한 번에! 😎

반응형

+ Recent posts