본문 바로가기
개발

🌈 PyCharm으로 시작하는 FastAPI 개발 여정 (초보자를 위한 가이드) 4편 ✨

by D-Project 2025. 3. 21.

 

안녕하세요! FastAPI와 PyCharm 개발 여정의 마지막 이야기, 4편이 찾아왔어요! 🎉 이번에는 우리가 만든 API를 배포하고 문서화하는 방법을 알아볼게요. 개발 초보자도 쉽게 따라할 수 있도록 차근차근 설명할게요! 💪

🔍 4편에서 배울 내용

  1. API 문서 커스터마이징하기
  2. 사용자 인증 추가하기
  3. Docker로 애플리케이션 컨테이너화하기
  4. 클라우드 서비스에 배포하기

📌 1. API 문서 커스터마이징하기

FastAPI는 자동으로 Swagger UI와 ReDoc 문서를 생성해주지만, 더 전문적인 문서를 위해 커스터마이징할 수 있어요! 먼저 main.py 파일의 FastAPI 인스턴스 생성 부분을 수정해볼게요:

app = FastAPI(
    title="Todo API",
    description="FastAPI로 만든 할 일 관리 API입니다! 📝",
    version="0.1.0",
    openapi_tags=[
        {
            "name": "todos",
            "description": "할 일 관리 작업",
        },
    ],
    contact={
        "name": "개발자 이름",
        "url": "https://yourwebsite.com",
        "email": "your.email@example.com",
    },
)

그리고 각 라우트에 태그를 추가해볼게요:

@app.post("/todos/", response_model=schemas.Todo, status_code=status.HTTP_201_CREATED, tags=["todos"])
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
    # 코드는 그대로...

나머지 라우트에도 같은 방식으로 tags=["todos"]를 추가해주세요!

이제 각 엔드포인트에 상세한 설명도 추가해봅시다:

@app.post("/todos/", response_model=schemas.Todo, status_code=status.HTTP_201_CREATED, tags=["todos"])
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db)):
    """
    새로운 할 일을 생성합니다.
    
    - **title**: 할 일 제목 (필수)
    - **description**: 할 일 설명 (선택)
    - **completed**: 완료 여부 (기본값: False)
    """
    # 코드는 그대로...

이런 식으로 각 엔드포인트에 설명(docstring)을 추가하면, Swagger UI와 ReDoc에 자세한 설명이 표시됩니다! 😊

📌 2. 사용자 인증 추가하기

이제 우리 API에 간단한 인증 기능을 추가해볼게요. OAuth2 비밀번호 흐름과 JWT 토큰을 사용할 거예요!

먼저 필요한 라이브러리를 설치해주세요:

pip install python-jose[cryptography] passlib[bcrypt]

그리고 security.py 파일을 생성하여 다음 코드를 추가해주세요:

from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

# 비밀 키 설정 (실제 프로덕션에서는 환경 변수나 설정 파일에서 불러오는 것이 좋아요)
SECRET_KEY = "나만의_비밀_키_여기에_입력하세요"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 비밀번호 해싱을 위한 컨텍스트
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2 스키마 설정
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# 비밀번호 검증 함수
def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

# 비밀번호 해싱 함수
def get_password_hash(password):
    return pwd_context.hash(password)

# 액세스 토큰 생성 함수
def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

# 토큰 검증 함수
async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="인증할 수 없습니다! 😢",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    return username

이제 schemas.py에 사용자 인증 관련 모델을 추가해주세요:

class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    username: Optional[str] = None

class User(BaseModel):
    username: str

그리고 main.py에 토큰 발급 엔드포인트를 추가해주세요:

from fastapi.security import OAuth2PasswordRequestForm
from security import get_password_hash, verify_password, create_access_token, get_current_user

# 간단한 사용자 데이터베이스 (실제로는 DB에 저장해야 해요)
fake_users_db = {
    "testuser": {
        "username": "testuser",
        "hashed_password": get_password_hash("password123"),
    }
}

@app.post("/token", response_model=schemas.Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or not verify_password(form_data.password, user["hashed_password"]):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="사용자 이름이나 비밀번호가 올바르지 않아요! 😢",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    access_token = create_access_token(
        data={"sub": user["username"]}
    )
    return {"access_token": access_token, "token_type": "bearer"}

이제 특정 엔드포인트에 인증을 적용해볼게요:

@app.post("/todos/", response_model=schemas.Todo, status_code=status.HTTP_201_CREATED, tags=["todos"])
def create_todo(todo: schemas.TodoCreate, db: Session = Depends(get_db), current_user: str = Depends(get_current_user)):
    """
    새로운 할 일을 생성합니다. (인증 필요)
    
    - **title**: 할 일 제목 (필수)
    - **description**: 할 일 설명 (선택)
    - **completed**: 완료 여부 (기본값: False)
    """
    # 코드는 그대로...

이제 할 일을 생성하려면 먼저 /token 엔드포인트에서 토큰을 받아서 인증해야 해요! 🛡️

📌 3. Docker로 애플리케이션 컨테이너화하기

이제 우리 애플리케이션을 Docker 컨테이너로 패키징해볼게요. 먼저 requirements.txt 파일을 생성하고 필요한 패키지를 명시해주세요:

fastapi==0.104.1
uvicorn==0.23.2
sqlalchemy==2.0.23
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6

그리고 루트 디렉토리에 Dockerfile을 생성하고 다음 내용을 추가하세요:

FROM python:3.9

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Docker 컨테이너를 빌드하려면 터미널에서 다음 명령어를 실행하세요 (Docker가 설치되어 있어야 해요):

docker build -t fastapi-todo-app .

그리고 컨테이너를 실행하려면:

docker run -d -p 8000:8000 fastapi-todo-app

이제 http://localhost:8000/docs에서 우리 API에 접근할 수 있어요! 🐳

📌 4. 클라우드 서비스에 배포하기

이제 우리 애플리케이션을 클라우드에 배포해볼게요. 여러 클라우드 서비스가 있지만, 여기서는 Heroku를 예로 들어볼게요! (무료 계정으로 시작할 수 있어요)

먼저 Procfile을 생성하고 다음 내용을 추가하세요:

web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-8000}

그리고 runtime.txt 파일을 생성하고 다음 내용을 추가하세요:

python-3.9.7

Heroku CLI를 설치하고, 다음 명령어로 배포할 수 있어요:

# Heroku에 로그인
heroku login

# 새 Heroku 앱 생성
heroku create fastapi-todo-app

# 코드 푸시 및 배포
git push heroku main

# 앱 열기
heroku open

이제 여러분의 API가 인터넷에 공개되었어요! 전 세계 어디서든 접근할 수 있답니다! 🌎

💡 보너스: CORS 설정하기

웹 프론트엔드에서 우리 API에 접근하려면 CORS(Cross-Origin Resource Sharing)을 설정해야 해요. main.py에 다음 코드를 추가해주세요:

from fastapi.middleware.cors import CORSMiddleware

# CORS 설정
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 실제 프로덕션에서는 구체적인 출처를 명시하는 것이 좋아요
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

🎁 마무리

축하해요! 여러분은 이제 FastAPI를 이용해 완전한 백엔드 API를 개발하고, 문서화하고, 인증을 추가하고, 컨테이너화하고, 배포하는 방법까지 배웠어요! 🎊

이 4부작 시리즈를 통해 여러분은:

  1. PyCharm과 FastAPI 기본 환경 설정 방법
  2. 다양한 엔드포인트와 매개변수 다루는 방법
  3. 데이터베이스 연결과 CRUD 작업 구현 방법
  4. API 문서화, 인증 추가, 컨테이너화, 배포 방법

을 배웠어요! 이제 여러분은 실제 프로젝트에서 FastAPI를 사용할 준비가 되었답니다! 👩‍💻

🔮 다음 단계는?

이제 다음과 같은 고급 주제를 더 공부해보시는 건 어떨까요?

  1. 웹소켓을 이용한 실시간 통신
  2. 백그라운드 작업과 스케줄링
  3. 마이크로서비스 아키텍처 구현
  4. GraphQL API 구현
  5. 테스트 자동화 및 CI/CD 파이프라인 구축

FastAPI 공식 문서(https://fastapi.tiangolo.com/)는 이러한 고급 주제에 대한 훌륭한 자료를 제공하고 있어요! 📚

여러분의 개발 여정이 즐겁고 성공적이길 바랍니다! 궁금한 점이나 질문이 있으시면 언제든지 댓글로 남겨주세요! 💕

이 시리즈가 여러분의 개발 여정에 도움이 되었다면 좋아요와 공유도 부탁드려요! 다음 시리즈에서 또 만나요~ 🚀