본문으로 건너뛰기
백엔드 기초집: Python FastAPILESSON 26

최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비

난이도초급
예상 시간35분
선수지식이전 강의

26강. 최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비

1. 이번 강의에서 해결할 문제

각 강의에서 만든 기능이 따로 동작해도 배포 가능한 API가 되지는 않습니다. 요청 흐름, DB 변경, 보안, 테스트, 실행 설정을 하나의 완료 기준으로 통합합니다.

2. 학습 목표

3. 핵심 개념

최종 요청 흐름은 Router → Pydantic → 인증·DB dependency → service/ORM → response model입니다. 완성 기준은 정상 응답뿐 아니라 잘못된 입력, 만료 token, 다른 사용자 소유권, 빈 검색, DB migration, 프로세스 재시작, 환경 변수 누락을 처리하는 것입니다.

랭킹은 게임별 사용자 최고 점수만 집계한다는 정책으로 통일합니다. 같은 사용자가 같은 게임을 여러 번 플레이해도 자신의 최고 점수 하나가 순위에 반영됩니다.

4. 단계별 코드 예시

파일 경로: game-ranking-api/

최종 폴더 구조
game-ranking-api/
├─ alembic/ # schema 변경 이력
├─ app/
│ ├─ models/ # User, GameRecord ORM
│ ├─ routers/ # auth, records, rankings, admin
│ ├─ schemas/ # 요청·응답 계약
│ ├─ services/ # 기록·랭킹 도메인 쿼리
│ ├─ config.py
│ ├─ database.py
│ ├─ dependencies.py
│ ├─ security.py
│ └─ main.py
├─ tests/
├─ .env.example
├─ alembic.ini
├─ requirements.txt
└─ README.md

파일 경로: game-ranking-api/app/routers/rankings.py

app/routers/rankings.py
from fastapi import APIRouter
from sqlalchemy import func, select

from app.models.record import GameRecord
from app.models.user import User

router = APIRouter(prefix="/rankings", tags=["rankings"])


@router.get("/{game_name}")
def game_ranking(game_name: str, db: DbSession, limit: int = 10) -> dict[str, object]:
personal_best = (
select(
GameRecord.user_id,
func.max(GameRecord.score).label("best_score"),
)
.where(GameRecord.game_name == game_name)
.group_by(GameRecord.user_id)
.subquery()
)
statement = (
select(User.username, personal_best.c.best_score)
.join(personal_best, personal_best.c.user_id == User.id)
.order_by(personal_best.c.best_score.desc(), User.username)
.limit(min(max(limit, 1), 100))
)
rows = db.execute(statement).all()
return {
"game_name": game_name,
"items": [
{"rank": index, "username": row.username, "score": row.best_score}
for index, row in enumerate(rows, start=1)
],
}

파일 경로: game-ranking-api/README.md

README.md
# Game Ranking API

## 실행
1. Python 3.13 가상환경 생성
2. `python -m pip install -r requirements.txt`
3. `.env.example`을 참고해 환경 변수 설정
4. `alembic upgrade head`
5. `python -m uvicorn app.main:app --host 0.0.0.0 --port 8000`

## 주요 API
- POST `/auth/register`, POST `/auth/token`
- GET/POST/PATCH/DELETE `/records`
- GET `/rankings/{game_name}`
- GET `/users/me`, GET `/health`

실행 위치: game-ranking-api/

python -m pip check
alembic upgrade head
alembic check
python -m pytest -q
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000

배포 환경에서는 reverse proxy 또는 플랫폼이 HTTPS를 종료하고, 프로세스 수와 DB connection pool 크기를 함께 계산합니다. 시작 명령과 health check path /health를 배포 설정에 등록합니다.

5. 코드가 동작하는 이유

subquery가 사용자별 최고 점수를 먼저 계산하고 User와 join해 이름을 가져옵니다. 정렬은 점수 내림차순, 동점은 사용자 이름으로 고정해 결과가 안정적입니다. 환경 변수와 migration이 코드·DB를 같은 버전으로 만들고 테스트가 핵심 계약을 배포 전에 확인합니다.

6. 자주 하는 실수와 해결법

7. 직접 실습

8. 이해 점검 질문 3개

9. 핵심 요약

MINI QUIZ

최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1다음 중 “최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비”의 핵심 요약을 실제 상황에 맞게 적용한 것은 무엇인가요?
  2. 문제 2“최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비” 실습 중 ‘배포 뒤 정상 요청만 확인합니다.’ 상황을 발견했습니다. 본문과 일치하는 설명은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

26강. 최종 프로젝트: 게임 기록·랭킹 REST API 완성 및 배포 준비 미완료 상태