FastAPI와 SQLAlchemy로 비동기 API 서버 구축
배경
사내 백오피스 API 서버를 Django REST Framework에서 FastAPI로 전환했다. 주된 이유는 성능과 타입 안정성이었다. 특히 외부 API 호출이 많은 엔드포인트에서 동기 처리의 한계가 명확했다.
FastAPI 선택 이유
- Pydantic 기반 자동 밸리데이션과 직렬화
- OpenAPI 문서 자동 생성
- asyncio 네이티브 지원
- 타입 힌팅으로 IDE 지원 우수
비동기 DB 연결 설정
SQLAlchemy 1.4부터 async를 공식 지원한다.
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
echo=True
)
AsyncSessionLocal = sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
)
async def get_db():
async with AsyncSessionLocal() as session:
yield session
실제 엔드포인트 구현
from fastapi import FastAPI, Depends
from sqlalchemy.future import select
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(
user_id: int,
db: AsyncSession = Depends(get_db)
):
result = await db.execute(
select(User).where(User.id == user_id)
)
user = result.scalars().first()
return user
성능 개선
동일한 트래픽 대비 응답 시간이 평균 40% 감소했다. 특히 외부 API 호출과 DB 쿼리가 섞인 로직에서 asyncio.gather로 병렬 처리하면서 효과가 컸다.
주의사항
- asyncpg 드라이버 필수 (psycopg2는 동기 전용)
- SQLAlchemy 쿼리 패턴이 1.4부터 변경됨 (
select()함수 사용) - 기존 동기 라이브러리는
run_in_executor로 래핑 필요
마무리
FastAPI의 학습 곡선은 낮은 편이었다. Django의 무거움이 부담스러운 프로젝트라면 충분히 고려할 만하다.