FastAPI는 빠르고 간결한 웹 애플리케이션을 개발하기 위해 설계된 프레임워크로, 데이터베이스와의 연동을 쉽게 처리할 수 있다. 그중에서도 SQLAlchemy는 가장 널리 사용되는 SQL toolkit 및 Object-Relational Mapping(ORM) 라이브러리로, Python 애플리케이션과 데이터베이스 간의 상호작용을 단순화해준다. 이 블로그 글에서는 FastAPI와 SQLAlchemy를 함께 사용하는 방법을 단계별로 설명한다.
1. FastAPI와 SQLAlchemy 소개
FastAPI는 Python의 최신 기능들을 활용해 비동기적으로 높은 성능을 제공하며, 빠른 개발과 유지보수를 가능하게 한다. 반면, SQLAlchemy는 SQL과 Python 간의 중간 계층으로, SQL 구문을 Python 코드로 작성할 수 있게 해준다. FastAPI와 SQLAlchemy를 함께 사용하면 웹 애플리케이션에서 데이터베이스 연동을 보다 쉽게 관리할 수 있다.
2. 프로젝트 설정 및 초기화
먼저, 필요한 패키지를 설치해야 한다. 여기에는 FastAPI, SQLAlchemy, 그리고 데이터베이스와 연결하기 위한 asyncpg
와 같은 드라이버가 포함된다.
pip install fastapi
pip install sqlalchemy
pip install psycopg2-binary
pip install uvicorn # 서버 실행을 위해
이제 프로젝트의 기본 구조를 설정한다.
myapp/
├── main.py
├── models.py
└── database.py
└── crud.py
└── schemas.py
3. SQLAlchemy 및 데이터베이스 설정
먼저, database.py
파일을 생성하고, 데이터베이스 연결 설정을 한다.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname"
engine = create_engine(SQLALCHEMY_DATABASE_URL, echo=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
여기서는 PostgreSQL을 예제로 사용했지만, 다른 데이터베이스를 사용할 경우 SQLALCHEMY_DATABASE_URL
을 변경하면 된다.
engine
: 데이터베이스와의 연결을 관리하는 객체이다.SessionLocal
: 데이터베이스 세션을 생성하는 데 사용된다.Base
: 모든 모델 클래스가 상속받을 기본 클래스이다.
4. SQLAlchemy 모델 정의하기
이제 models.py
파일을 생성하여 데이터베이스 모델을 정의합니다. SQLAlchemy 모델은 Python 클래스로 정의되며, 데이터베이스의 테이블 구조를 반영한다.
from sqlalchemy import Column, Integer, String
from .database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
이 예제에서는 User
라는 모델을 정의했다. 이 모델은 users
라는 테이블에 매핑되며, 각 속성은 테이블의 컬럼을 나타낸다.
5. Pydantic 모델 정의
schemas.py
파일은 사용자 입력과 응답 데이터를 정의하는 Pydantic 모델을 포함한다.
from pydantic import BaseModel
class UserBase(BaseModel):
email: str
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
class Config:
orm_mode = True
UserBase
: 공통적으로 사용되는name
과email
필드를 포함한 기본 클래스이다.UserCreate
:UserBase
를 상속받아 사용자를 생성할 때 필요한password
필드를 추가한다.User
: 데이터베이스에서 조회된 사용자 정보를 클라이언트에 반환할 때 사용된다.orm_mode = True
로 설정하면 SQLAlchemy 모델과 호환된다.
6. CRUD 로직 정의
crud.py
파일은 데이터베이스와 상호작용하는 함수를 정의한다. 이를 통해 데이터베이스 작업을 라우트 함수에서 분리할 수 있다.
from sqlalchemy.orm import Session
from . import models, schemas
def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()
def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()
def create_user(db: Session, user: schemas.UserCreate):
hashed_password = user.password # 여기서 실제로는 해싱을 해야 합니다.
db_user = models.User(name=user.name, email=user.email, hashed_password=hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
7. FastAPI와 SQLAlchemy 연동하기
main.py
파일에서 FastAPI 애플리케이션을 설정하고, 데이터베이스와의 연동을 처리한다.
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from . import models, database
app = FastAPI()
# 데이터베이스와 연결을 설정
models.Base.metadata.create_all(bind=database.engine)
# 의존성 주입: 요청마다 데이터베이스 세션을 생성
def get_db():
db = database.SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/users/", response_model=User)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = models.User(email=user.email, hashed_password=user.hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
@app.get("/users/{user_id}", response_model=User)
def read_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return user
주요 개념 설명:
get_db
: 요청마다 새로운 데이터베이스 세션을 생성하여, 이 세션이 모든 데이터베이스 작업에 사용되도록 한다.yield
를 사용해 세션을 반환하고, 작업이 끝난 후 세션을 닫는다.Depends
: FastAPI의 의존성 주입 시스템을 사용해get_db
함수를 경로 함수에 주입한다.create_user
: 새로운 사용자를 데이터베이스에 추가하는 경로 함수이다.read_user
: 특정 사용자를 조회하는 경로 함수이다.
8. 비동기 SQLAlchemy 사용하기 (선택사항)
FastAPI는 비동기 처리를 지원하기 때문에, 비동기적으로 SQLAlchemy를 사용할 수도 있다. 이를 위해 databases
패키지와 asyncpg
드라이버를 사용한다.
pip install databases asyncpg
비동기 설정을 적용한 후에는 데이터베이스 작업을 비동기적으로 수행할 수 있으며, 이는 응답 시간을 줄이고 서버의 동시 처리 능력을 향상시킬 수 있다.