이 글은 FastAPI, Pydantic 2.x, 그리고 SQLAlchemy를 처음 접하는 개발자부터 실무에 활용하고자 하는 분들을 대상으로 합니다.
- FastAPI 기반 웹 API를 만들 때 Pydantic 2.x 모델을 활용한 데이터 검증, SQLAlchemy ORM과의 자연스러운 연동 방식을 단계별로 이해할 수 있도록 돕습니다.
- Python 기초 문법을 알고 있고, 웹 프레임워크 또는 ORM 사용 경험이 약간 있는 개발자. 초등학생도 이해할 수 있을 정도로 친절한 설명을 제공합니다.
FastAPI 개요
FastAPI는 현대적인 비동기(Asynchronous) 웹 프레임워크로, Starlette를 기반으로 하고, Pydantic을 통해 입력 검증과 직렬화를 제공하여 빠르고 안정적인 API를 구축할 수 있습니다.
- 주요 특징
- 비동기 지원:
async def
로 작성한 경로 함수(route)가 기본 비동기 처리 - 자동 문서화: OpenAPI(Swagger)와 ReDoc을 자동 생성
- 높은 성능: Uvicorn + ASGI 기반으로 빠른 처리 속도
- 비동기 지원:
- 사용 장점
- 타입 힌트를 적극 활용한 유효성 검사
- 생산성과 가독성 모두 제고
- 최소한의 설정으로 바로 사용 가능
Pydantic 2.x 개념 이해
Pydantic은 Python 타입 힌트를 기반으로 런타임 시 데이터 검증(validation)과 직렬화(serialization)를 수행합니다. 2.x 버전은 더 가볍고 빠른 성능을 목표로 핵심 구조가 일부 변경되었습니다.
BaseModel 사용법
- 모델 정의
from pydantic import BaseModel, Field class User(BaseModel): id: int name: str = Field(..., max_length=50) signup_ts: datetime | None = None
- 인스턴스 생성
user = User(id=1, name="Alice")
필드 검증(Validation)
- 기본 검증: 타입이 일치하지 않으면
ValidationError
발생 - 제약 조건:
Field
파라미터로min_length
,max_length
,gt
,lt
등 설정 가능 - 커스텀 검증:
@field_validator
데코레이터로 복잡한 규칙 적용
직렬화와 역직렬화
- 직렬화:
model.json()
또는model.dict()
로 Python 객체 → JSON/Dict 변환 - alias: 필드 이름을 외부와 다르게 매핑 가능
- export 옵션:
exclude_none=True
로None
필드 자동 제외
SQLAlchemy 소개
SQLAlchemy는 Python ORM(Object-Relational Mapping) 라이브러리로, 데이터베이스 테이블을 Python 클래스로 다룰 수 있게 해 줍니다.
엔진과 세션 설정
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
모델 정의와 매핑
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class UserORM(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
Pydantic과 SQLAlchemy 연동
Pydantic 2.x와 호환되는 SQLAlchemy 버전(1.4+)을 사용하면, from_orm
옵션으로 SQLAlchemy ORM 인스턴스를 Pydantic 모델로 쉽게 변환할 수 있습니다.
from_orm 옵션
- Pydantic 모델 설정
class UserSchema(BaseModel): id: int name: str model_config = ConfigDict(from_attributes=True)
- ORM → Pydantic 변환
db_user = session.query(UserORM).first() user_data = UserSchema.from_orm(db_user)
SQLModel 대안
- SQLModel: FastAPI의 창시자 Sebastián Ramírez가 만든, Pydantic + SQLAlchemy를 합친 통합 라이브러리
- 장점: 별도 연동 설정 불필요,
from_orm
이 기본 - 단점: 커스터마이징 한계
CRUD 구현 예제
- Create
@app.post("/users/", response_model=UserSchema) def create_user(user: UserSchema, db: Session = Depends(get_db)): db_user = UserORM(**user.model_dump()) db.add(db_user); db.commit(); db.refresh(db_user) return db_user
- Read
@app.get("/users/{user_id}", response_model=UserSchema) def read_user(user_id: int, db: Session = Depends(get_db)): return db.get(UserORM, user_id)
- Update
@app.put("/users/{user_id}", response_model=UserSchema) def update_user(user_id: int, user: UserSchema, db: Session = Depends(get_db)): db_user = db.get(UserORM, user_id) for k, v in user.model_dump(exclude_unset=True).items(): setattr(db_user, k, v) db.commit(); db.refresh(db_user) return db_user
- Delete
@app.delete("/users/{user_id}") def delete_user(user_id: int, db: Session = Depends(get_db)): db_user = db.get(UserORM, user_id) db.delete(db_user); db.commit() return {"ok": True}
FastAPI 라우터와 의존성 주입
- 라우터 구조:
@app.get()
,@app.post()
등 데코레이터로 엔드포인트 선언 - 의존성 주입:
Depends(get_db)
로 DB 세션, 인증, 설정 등을 간편하게 삽입
def get_db():
db = SessionLocal();
try: yield db
finally: db.close()
에러 처리 및 응답 모델
- HTTPException
from fastapi import HTTPException if not db_user: raise HTTPException(status_code=404, detail="User not found")
- 응답 모델:
response_model
파라미터로 자동 검증 및 문서화
설정 관리 및 환경 변수
- pydantic-settings
from pydantic_settings import BaseSettings class Settings(BaseSettings): database_url: str class Config: env_file = ".env" settings = Settings()
- .env 파일: 민감한 정보는 분리합니다.
테스트 작성 팁
- pytest 사용
from fastapi.testclient import TestClient client = TestClient(app) def test_create_user(): response = client.post("/users/", json={"id":1,"name":"Alice"}) assert response.status_code == 200
- 테스트 DB: 별도 SQLite 인메모리 사용
성능 최적화 전략
- 데이터베이스 튜닝: 인덱싱, 쿼리 최적화
- 캐싱: Redis 활용, FastAPI의 BackgroundTask
배포 및 운영 고려사항
- Docker 이미지 구성:
Dockerfile
과docker-compose.yml
- Alembic 마이그레이션:
alembic init alembic alembic revision --autogenerate -m "init" alembic upgrade head
- CI/CD: GitHub Actions, Jenkins 등 연동
결론 및 요약
지금까지 FastAPI, Pydantic 2.x, 그리고 SQLAlchemy를 연동해 실무 API를 만드는 데 핵심이 되는 개념과 문법을 살펴보았습니다.
- 핵심 요약:
- Pydantic으로 입력 검증 및 직렬화
- SQLAlchemy ORM과
from_orm
옵션으로 매끄러운 모델 변환 - FastAPI에서 의존성 주입과 자동 문서화 활용
FastAPI에 Pydantic, SQLAlchemy를 연동해, 견고하고 확장성 있는 Python 기반 API 서버를 구축해 보시길 바랍니다!