๐ ์ฝ 3๋ถ ์ฝ๋ ๋ฐ ์์๋ฉ๋๋ค
์ด์ ๊ธ ๋ณด๊ธฐ(FastAPI ๋ณด์ OAuth2, JWT)
์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ์์ ์ ๋ณด, ๊ฒ์๊ธ, ๋๊ธ, ์ํ ๋ฑ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๊ธฐ ์ํด์๋ ์์ ์ ์ด๊ณ ํจ์จ์ ์ธ DB ์ฐ๋์ด ํ์๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ FastAPI์์ MySQL๊ณผ SQLAlchemy๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๋ํ๊ณ , CRUD(์์ฑ, ์กฐํ, ์์ , ์ญ์ ) ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ฐจ๊ทผ์ฐจ๊ทผ ์ค๋ช ํ๊ฒ ๋ค. ๊ฐ๋ฐ ํ๊ฒฝ์ Windows, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ MySQL, ORM์ SQLAlchemy๋ฅผ ์ฌ์ฉํ๋ค.
โ๏ธ ํ๊ฒฝ ์ค์ ํ๊ธฐ
๋จผ์ ํ์ํ ํจํค์ง๋ฅผ ์ค์นํด์ผ ํ๋ค. ์๋ ๋ช ๋ น์ด๋ฅผ ํฐ๋ฏธ๋(cmd ํน์ PowerShell)์์ ์คํํ์.
pip install fastapi[all] sqlalchemy pymysql
sqlalchemy
: ORM์ ์ํ ํต์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌpymysql
: MySQL ๋๋ผ์ด๋ฒ ์ญํfastapi[all]
: FastAPI์ ํจ๊ป Uvicorn ๋ฑ ํ์ํ ์ข ์์ฑ ํฌํจ
MySQL ์๋ฒ๋ ๋ก์ปฌ ํน์ ์๊ฒฉ์ ์ค์น๋์ด ์์ด์ผ ํ๋ฉฐ, user
, password
, database
, host
, port
์ ๋ณด๋ฅผ ์๊ณ ์์ด์ผ ํ๋ค.
๐งฉ DB ์ฐ๊ฒฐ ์ค์ – database.py
๋ค์์ SQLAlchemy์ ์์ง๊ณผ ์ธ์ ์ ์ค์ ํ๋ ์ฝ๋์ด๋ค.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# MySQL ์ ์ ๋ฌธ์์ด
DATABASE_URL = "mysql+pymysql://username:password@localhost:3306/testdb"
engine = create_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
์ฌ๊ธฐ์ username
, password
, testdb
๋ ๊ฐ์ ํ๊ฒฝ์ ๋ง๊ฒ ๋ฐ๊พธ์ด์ผ ํ๋ค. echo=True
๋ SQL ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํด์ค์ ๋๋ฒ๊น
์ ์ ์ฉํ๋ค.
๐ฆ ๋ชจ๋ธ ์ ์ – models.py
๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ๊ณผ ๋งคํ๋๋ ํด๋์ค๋ฅผ SQLAlchemy๋ก ์ ์ํ์.
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(50), nullable=False)
email = Column(String(100), unique=True, nullable=False)
์ด์ User
๋ชจ๋ธ์ users
๋ผ๋ ํ
์ด๋ธ๋ก ๋ณํ๋์ด MySQL์ ์์ฑ๋ ์ ์๋ค.
๐ ์ด๊ธฐํ ๋ฐ DB ํ ์ด๋ธ ์์ฑ
main.py
๋๋ ๋ณ๋์ ์ด๊ธฐํ ์คํฌ๋ฆฝํธ์์ ์๋ ์ฝ๋๋ฅผ ์คํํ์ฌ ํ
์ด๋ธ์ ์์ฑํ์.
from database import engine
from models import Base
Base.metadata.create_all(bind=engine)
์ด ์ฝ๋๋ฅผ ํตํด MySQL์ testdb
๋ฐ์ดํฐ๋ฒ ์ด์ค์ users
ํ
์ด๋ธ์ด ์์ฑ๋๋ค.
๐จ CRUD ๊ตฌํ – crud.py
ORM์ ํ์ฉํ์ฌ ๋ฐ์ดํฐ ์กฐ์ ํจ์๋ค์ ๊ตฌํํด๋ณด์.
from sqlalchemy.orm import Session
from models import User
def create_user(db: Session, name: str, email: str):
db_user = User(name=name, email=email)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
def get_user(db: Session, user_id: int):
return db.query(User).filter(User.id == user_id).first()
def get_users(db: Session, skip: int = 0, limit: int = 10):
return db.query(User).offset(skip).limit(limit).all()
def update_user(db: Session, user_id: int, name: str):
user = db.query(User).filter(User.id == user_id).first()
if user:
user.name = name
db.commit()
db.refresh(user)
return user
def delete_user(db: Session, user_id: int):
user = db.query(User).filter(User.id == user_id).first()
if user:
db.delete(user)
db.commit()
return user
์ด์ ๊ธฐ๋ณธ์ ์ธ ๋ฐ์ดํฐ ์กฐ์ ์์ ์ ๋ชจ๋ ์ค๋น๋์๋ค.
๐ FastAPI์ ์ฐ๊ฒฐ – main.py
API ๋ผ์ฐํ ๊ณผ ์์ฒญ ์ฒ๋ฆฌ ์ฝ๋๋ฅผ ์ถ๊ฐํด๋ณด์.
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from database import SessionLocal
from models import User
import crud
from pydantic import BaseModel
app = FastAPI()
# DB ์ธ์
์ฃผ์
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
๐ฌ ์ ์ ์์ฑ
class UserCreate(BaseModel):
name: str
email: str
@app.post("/users/")
def create_user(user: UserCreate, db: Session = Depends(get_db)):
return crud.create_user(db, name=user.name, email=user.email)
๐ฅ ์ ์ ๋ชฉ๋ก ์กฐํ
@app.get("/users/")
def read_users(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
return crud.get_users(db, skip=skip, limit=limit)
๐ค ์ ์ ๋จ๊ฑด ์กฐํ
@app.get("/users/{user_id}")
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user
โ๏ธ ์ ์ ์์
class UserUpdate(BaseModel):
name: str
@app.put("/users/{user_id}")
def update_user(user_id: int, user: UserUpdate, db: Session = Depends(get_db)):
return crud.update_user(db, user_id, user.name)
โ ์ ์ ์ญ์
@app.delete("/users/{user_id}")
def delete_user(user_id: int, db: Session = Depends(get_db)):
return crud.delete_user(db, user_id)
โก ๋น๋๊ธฐ DB ์ฐ๋์ ๋ํด ์ ๊น
SQLAlchemy๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋๊ธฐ ๋ฐฉ์์ด๋ค. FastAPI๋ ๋น๋๊ธฐ ์น ํ๋ ์์ํฌ์ด์ง๋ง, SQLAlchemy์ ํจ๊ป ์ฌ์ฉํ ๋๋ ์ฃผ๋ก ๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ค. ๋ง์ฝ ๋น๋๊ธฐ DB ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค๋ฉด, SQLModel
+ async SQLAlchemy
, ํน์ Tortoise ORM
๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํ๋ ค๋ฉด async def
๋ผ์ฐํธ์ await
ํธ์ถ์ด ํ์ํ๊ณ , DB ์ธ์
๋ async_sessionmaker
๋ก ์ฒ๋ฆฌํด์ผ ํ๋ค. ์ค์ ์ด ๋ณต์กํด์ง๋ ๋์ ๋์ ์ฒ๋ฆฌ ์ฑ๋ฅ์ ๊ธฐ๋ํ ์ ์๋ค.
๐ ์ ๋ฆฌํ๋ฉฐ
์ด๋ฒ ํฌ์คํธ์์๋ Windows ํ๊ฒฝ์์ FastAPI์ MySQL์ ์ฐ๋ํ๋ ๋ฐฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ SQLAlchemy ORM์ ํตํด ํ ์ด๋ธ ์์ฑ๋ถํฐ CRUD ๊ตฌํ๊น์ง ์ ๊ณผ์ ์ ์์๋ณด์๋ค. FastAPI์ ์ฅ์ ์ ๊ทธ ์ ์ฐ์ฑ๊ณผ ํ์ฅ์ฑ์ ์๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋ ๋ํ ๊ทธ ์ค ํ๋๋ค. ํนํ ์ค์ ์ด์ ํ๊ฒฝ์์๋ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ, ํธ๋์ญ์ ์ฒ๋ฆฌ, ORM ํ์ฉ ๋ฅ๋ ฅ์ด ์ค์ํ๋ฏ๋ก, ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํํํ ๋ค์ง๋ ๊ฒ์ด ์ค์ํ๋ค.
์ด์ ์ฌ๋ฌ๋ถ์ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ DB์ ์ ์ฅํ๊ณ ๋ถ๋ฌ์ค๋ฉฐ, ์น ์๋น์ค์ ํต์ฌ ๊ธฐ๋ฅ์ ๊ตฌ์ถํ ์ ์๊ฒ ๋์๋ค. ๋ค์ ๋จ๊ณ์์๋ ์ธ์ฆ ์ฒ๋ฆฌ, ํ์ด์ง, ๊ฒ์ ๊ธฐ๋ฅ๊น์ง ํ์ฅํด๋ณด์.
FastAPI ๊ณต์ ๋ฌธ์ : https://fastapi.tiangolo.com/ko/
