FastAPI는 현대적인 웹 API를 구축하는 데 최적화된 Python 웹 프레임워크로, 성능과 빠른 개발 속도를 제공합니다. FastAPI의 주요 장점 중 하나는 데이터 유효성 검사와 자동 문서 생성을 위한 Pydantic의 사용입니다. 본 글에서는 FastAPI에서 응답 스키마를 정의하는 방법과 다양한 응답 타입을 설정하는 방법에 대해 깊이 있게 알아보겠습니다.
1. FastAPI와 Pydantic 소개
FastAPI는 백엔드 서버 개발을 위한 고성능 프레임워크로, RESTful API를 간편하게 구축할 수 있게 도와줍니다. FastAPI의 핵심 특징 중 하나는 Pydantic을 통한 데이터 유효성 검사 및 직렬화입니다. Pydantic을 사용하면 데이터 모델을 선언적으로 정의할 수 있으며, 데이터의 유효성을 체크할 수 있습니다.
예를 들어, 사용자의 정보를 담는 데이터 모델을 아래와 같이 정의할 수 있습니다.
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: str
2. FastAPI에서의 응답 스키마 정의
FastAPI에서 API의 응답을 정의하려면 Pydantic 모델을 사용합니다. 이 모델은 API가 클라이언트에게 반환하는 데이터의 구조를 정의합니다. 이렇게 하면 일관된 응답 형식을 보장하고 클라이언트는 예측 가능한 방식으로 데이터를 처리할 수 있습니다.
다음은 사용자의 정보를 반환하는 API 엔드포인트를 만드는 예제입니다.
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
return User(id=user_id, name="John Doe", email="johndoe@example.com")
위 코드에서 response_model=User
를 설정함으로써 FastAPI는 이 API가 반환하는 데이터가 User
모델의 형식에 맞도록 자동으로 유효성 검사를 수행합니다. 그리고 스웨거 문서에서도 이 모델의 구성 정보를 확인할 수 있습니다.
3. 복잡한 응답 모델 정의
API의 응답은 때로는 단순하지 않을 수 있습니다. 여러 개의 모델을 포함한 복잡한 응답 구조를 정의해야 할 수도 있습니다. 예를 들어, 게시물과 그에 대한 댓글을 포함하는 구조를 생각해 보겠습니다.
class Comment(BaseModel):
id: int
content: str
user_id: int
class Post(BaseModel):
id: int
title: str
content: str
comments: List[Comment] # 댓글 목록
이러한 모델을 사용하여 게시물 정보를 반환하는 엔드포인트를 정의할 수 있습니다.
from typing import List
@app.get("/posts/{post_id}", response_model=Post)
async def get_post(post_id: int):
comments = [Comment(id=1, content="Great post!", user_id=1),
Comment(id=2, content="Thanks for sharing!", user_id=2)]
return Post(id=post_id, title="My First Post", content="This is the content.", comments=comments)
4. 응답 타입 정의와 자동 문서화
FastAPI는 자동으로 API 문서를 생성합니다. 위의 예제에서 API의 메타데이터는 FastAPI가 자동으로 생성하여 스웨거(Swagger)와 ReDoc 문서화 도구에서 확인할 수 있습니다. 응답 모델을 정의함으로써 클라이언트는 API를 사용할 때 어떤 형태의 데이터를 받을 수 있는지 명확하게 알 수 있습니다.
또한, FastAPI는 충분한 API 문서를 자동으로 제공하므로 프론트엔드 개발자가 필요한 API 정보를 쉽게 확인할 수 있습니다. 아래와 같이 문서화된 내용을 확인할 수 있습니다.
uvicorn main:app --reload
브라우저에서 http://127.0.0.1:8000/docs
를 열면 Swagger UI를 통해 API의 모든 엔드포인트와 그 응답 형태를 확인할 수 있습니다.
5. 응답 시나리오: 성공, 실패 응답
실제 애플리케이션에서는 성공적인 응답뿐만 아니라 오류 처리도 포함되어야 합니다. FastAPI는 HTTPException
을 사용하여 오류 응답을 정의할 수 있습니다. 아래 예시는 사용자가 존재하지 않을 경우 404 오류 응답을 반환하는 방법을 보여줍니다.
from fastapi import HTTPException
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
if user_id != 1: # 존재하지 않는 사용자 ID
raise HTTPException(status_code=404, detail="User not found")
return User(id=user_id, name="John Doe", email="johndoe@example.com")
5.1. 커스텀 오류 응답 모델
또한, 오류 발생 시에 반환하는 커스텀 응답 모델을 정의할 수도 있습니다. 예를 들어, 오류 응답을 나타내는 모델을 정의하고 이를 사용하여 일관된 오류 메시지를 클라이언트에 전달할 수 있습니다.
class ErrorResponse(BaseModel):
detail: str
status_code: int
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail, "status_code": exc.status_code},
)
위와 같이 설정하면, 모든 HTTPException에 대해 일관된 구조의 오류 응답을 제공할 수 있습니다. 클라이언트에서는 응답을 쉽게 처리할 수 있습니다.
6. 응답 스키마와 API 버전 관리
API를 운영하다 보면 스키마가 변경되는 경우가 발생할 수 있습니다. 이를 잘 관리하기 위해 API 버전 관리를 고려해야 합니다. FastAPI는 경로에 버전 정보를 추가하여 서로 다른 버전의 API를 동시에 운영할 수 있습니다.
app_v1 = FastAPI()
app_v2 = FastAPI()
@app_v1.get("/users/{user_id}", response_model=User)
async def get_user_v1(user_id: int):
return User(id=user_id, name="John Doe", email="janedoe@example.com")
@app_v2.get("/users/{user_id}", response_model=User)
async def get_user_v2(user_id: int):
return User(id=user_id, name="Jane Doe", email="johndoe@example.com")
# Uvicorn을 통해 앱 실행
# uvicorn main:app_v1 --reload
# uvicorn main:app_v2 --reload
이렇게 각각의 버전마다 다른 응답을 제공할 수 있으므로, 기존 API를 사용하는 클라이언트는 새로운 변화에 영향을 받지 않고, 점진적으로 업데이트할 수 있습니다.
7. 결론
FastAPI는 그 자체의 뛰어난 성능과 직관적인 문서화, 유효성 검사 기능으로 인해 데이터 기반 애플리케이션을 개발하는 데 매우 유용한 도구입니다. 본 포스트에서는 FastAPI에서 응답 스키마를 정의하는 방법과 다양한 응답 타입 처리 방식을 자세히 살펴보았습니다.
스키마 정의는 API의 안정성과 일관성을 보장하는 데 매우 중요하며, 특히 여러 클라이언트 앱에서 사용할 때 그 중요성이 더욱 두드러집니다. FastAPI를 통해 빠르고 효율적으로 API를 구축하고 관리하는 방법을 이해하는 데 도움이 되었기를 바랍니다. 이제 여러분은 FastAPI를 사용하여 강력한 백엔드 시스템을 구축할 준비가 되었습니다!