코드의 여백

[FastAPI] Todo 예제로 배우는 RESTful API 설계

by rowing0328

※ 이 글은 이노그리드 교육 과정의 일부로, 저만의 관점과 해석을 더해 작성되었습니다.

 

Intro

이전 글에서 FastAPI 기본기와 APIRouter로 라우팅을 분리하는 방법까지 배워봤다.

 

이번에는 한 단계 더 나아가 실제로 "할 일(Todo) API"를 직접 만들어보며,
다음과 같은 핵심 포인트들을 정리해보려 한다:

  • Restful 설계
  • Pydantic 모델 도입
  • Path/Query 활용
  • 응답 모델/데이터 필터링
  • HTTP 오류 처리

 

이런 실무 핵심 포인트를 단계별로 정리해 본다.

처음 FastAPI 실전 프로젝트를 설계하거나,

실제 API 품질을 끌어올리고 싶은 분께 도움이 되길 바란다.

 

 

할 일(Todo) 서비스, RESTful 하게 설계하기

FastAPI에서 가장 기본이 되는 구조는 "라우팅"이다.

이번 실습에서는 할 일 추가, 조회, 수정, 삭제 등

RESTful하게 주소와 동작을 정리한다.

 

[ 예제 코드 ]

from fastapi import APIRouter
from typing import List

router = APIRouter(prefix="/todos", tags=["todos"])

@router.post("/", summary="할 일 추가")
def create_todo(...): ...

@router.get("/", summary="할 일 전체 목록")
def list_todos(...): ...

@router.get("/{todo_id}", summary="할 일 상세조회")
def get_todo(todo_id: int): ...

@router.put("/{todo_id}", summary="할 일 수정")
def update_todo(todo_id: int, ...): ...

@router.delete("/{todo_id}", summary="할 일 삭제")
def delete_todo(todo_id: int): ...

 

Restful 설계 원칙대로 아래와 같이 일관성 있게 설계한다:

  • 목록은 GET /todos
  • 등록은 POST /todos
  • 단건조회는 GET /todos/{id}
  • 수정은 PUT /todos/{id}
  • 삭제는 DELETE /todos/{id}

 

검색 등 특수 기능은 일반적으로 GET /todos/search처럼 별도 경로로 먼저 선언한다.

 

 

Pydantic으로 데이터 모델과 검증 자동화

FastAPI의 진짜 강점은 Pydantic 모델을 활용한 데이터 유효성 자동 검증이다.

 

예를 들어 Todo의 기본 정보는 다음처럼 작성할 수 있다.

from pydantic import BaseModel, Field
from typing import Optional

class Todo(BaseModel):
    id: int
    title: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = Field(None, max_length=500)
    is_done: bool = False
  • 타입/필수성/길이 등 유효성 조건을 코드 한 줄로 지정할 수 있다.
  • API 호출 시 잘못된 값이 오면, 자동으로 "400 에러"와 상세 메시지가 반환된다.
  • id 필드는 응답(response)에만 사용, 등록/수정 등에는 별도 모델 분리

 

 

중첩 모델·수정 모델로 역할 분리

등록할 때와 수정할 때,

모든 필드가 필요한 게 아니다.

 

예를 들어,

  • 새로 등록할 때는 title, description만 필요 (id는 필요 없음)
  • 수정할 때는 일부 필드만 받을 수 있음

 

그래서 다음처럼 중첩/수정 모델을 별도로 만든다.

class TodoCreate(BaseModel):
    title: str = Field(..., min_length=1)
    description: Optional[str] = None

class TodoUpdate(BaseModel):
    title: Optional[str] = Field(None, min_length=1)
    description: Optional[str] = None
    is_done: Optional[bool] = None
  • 각 API에서 적절한 모델을 사용하면, 불필요한 필드 요구를 없애고, 자동 문서화에도 정확히 반영된다.

 

 

Path & Query 매개변수 세밀하게 다루기

FastAPI의 또 하나의 실전은 Path, Query 클래스로

입력값 검증과 문서화 메타 정보를 더 세밀하게 컨트롤하는 것이다.

 

[ 예제 코드 ]

from fastapi import Path, Query

@router.get("/{todo_id}")
def get_todo(
    todo_id: int = Path(..., title="Todo ID", ge=1, description="할 일의 고유 번호")
):
    ...
    
@router.get("/search")
def search_todos(
    keyword: str = Query(..., min_length=1, max_length=30, description="검색어")
):
    ...
  • Path, Query를 사용하면 입력값 제한, 설명, 예시 등 문서화도 자동 반영된다.
  • todo_id는 1 이상이어야만 하도록 제한한다.
  • keyword는 최소 1자, 최대 30자로 제한한다.

 

라우터 선언 순서 주의

/todos/search 등 구체적인 경로를

/todos/{todo_id}(경로 매개변수) 보다 반드시 먼저 선언해야

경로 충돌을 방지할 수 있다.

 

 

응답과 데이터 필터링

FastAPI에서는 각 API의 반환 데이터 구조도 response_model로 명확히 지정할 수 있다.

 

[ 예제 코드 ]

class TodoSummary(BaseModel):
    title: str
    is_done: bool

@router.get("/summaries", response_model=List[TodoSummary])
def list_todo_summaries(): ...
  • 불필요한 내부 데이터(id 등)를 빼거나 사용자 요구에 맞는 "커스텀 응답"을 쉽게 만들 수 있다.

 

 

HTTP 오류 처리 및 표준화

실제 실무 API에서는

적절한 HTTP 상태 코드와 에러 메시지 전달이 매우 중요하다.

 

FastAPI에서는 HTTPException을 활용해

시나리오별로 정확한 코드와 메시지를 반환한다.

 

[ 예제 코드 ]

from fastapi import HTTPException

@router.get("/{todo_id}")
def get_todo(todo_id: int):
    todo = db.get(todo_id)
    if not todo:
        raise HTTPException(status_code=404, detail="할 일을 찾을 수 없음")
    return todo

@router.post("/", status_code=201)
def create_todo(...):
    ...
  • 404 Not Found, 201 Created, 200 OK 등 시나리오별 올바른 상태 코드를 사용
  • 에러 발생 시 클라이언트가 명확한 원인을 확인 가능 → 신뢰성/예측성 향상

 

 

마무리

이번 글에서는 FastAPI로 간단한 Todo API를 만들면서,

실무에서 자주 마주치는 핵심 개념들을 단계적으로 정리했다.

 

단순히 작동하는 API를 넘어서,

읽기 쉽고 유지보수하기 좋은 구조를 갖춘 API를 만드는 데 집중했다.

 

FastAPI는 이런 설계를 빠르게 구현할 수 있도록 돕는 훌륭한 프레임워크다.

이번 내용을 바탕으로 첫 프로젝트를 더 탄탄하게 설계할 수 있기를 바란다.

 

다음 글에서는 데이터베이스 연동을 다뤄볼 예정이다.

 

 

참고 자료:

FastAPI Official Web Site - Path Parameters

 

Path Parameters - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

 

FastAPI Official Web Site - Query Parameters

 

Query Parameters - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

블로그의 정보

코드의 여백

rowing0328

활동하기