Alroha

[스나이퍼팩토리] 카카오클라우드 - 클라우드 개발자 교육 6주차(3) 본문

IT/Kakao cloud 부트캠프

[스나이퍼팩토리] 카카오클라우드 - 클라우드 개발자 교육 6주차(3)

헤이로하 2025. 9. 16. 16:28

REST & FastAPI

(REST 아키텍처, FastAPI·Uvicorn·APIRouter 관계, 경로 매개변수, API 문서(Swagger/Redoc), 응답 유형 & 헤더, 디자인 패턴)


📅 REST와 FastAPI 기초

🧩 REST 개념 요약

아키텍처 스타일 웹 서비스 설계 원칙의 모음 “메뉴판(API 문서)에서 음식(리소스) 고르고 주문(요청) → 음식(응답) 받기”
자원(Resource) 명사형으로 표현, URI로 식별 /products/123, /users/42/orders/7
표현(Representation) 같은 자원을 JSON, XML, HTML 등 여러 표현으로 주고받음 웹: HTML, 앱: JSON
상태 전이(State Transfer) 링크를 따라 리소스 간 이동하며 애플리케이션 상태 변화 목록 → 상세 → 장바구니 → 결제
무상태성(Stateless) 요청은 독립적, 서버는 클라이언트 상태 저장 X 매 요청에 토큰 포함
통합 인터페이스 일관된 조작 방식(보통 HTTP) 모든 가전의 전원 버튼처럼 일관성

RESTful vs Non-RESTful 예시

# RESTful
GET /users/123
POST /users
PATCH /users/123
DELETE /users/123

# Non-RESTful (행위 동사 노출, 파라미터 위주)
GET /getUser?id=123

🧭 FastAPI · Uvicorn · APIRouter 

  • FastAPI: 앱 프레임워크(라우팅, 요청/응답, 검증, 의존성 주입, 문서화)
  • Uvicorn: ASGI 서버(실제 HTTP 서버, 비동기 고성능)
  • APIRouter: 라우트를 기능별 모듈로 분리/조합
[Client] ⇄ HTTP ⇄ [Uvicorn] ⇄ ASGI ⇄ [FastAPI(App)] ⇄ [APIRouter…]

실습 

# app/main.py
from fastapi import FastAPI, APIRouter
from pydantic import BaseModel

app = FastAPI(title="Todo API")

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

class Todo(BaseModel):
    id: int
    text: str
    done: bool = False

DB = {1: Todo(id=1, text="REST 복습")}

@router.get("", response_model=list[Todo])
def list_todos():
    return list(DB.values())

@router.get("/{todo_id}", response_model=Todo)
def get_todo(todo_id: int):
    return DB[todo_id]

app.include_router(router)

실행

uvicorn app.main:app --reload
# 문서: http://127.0.0.1:8000/docs (Swagger) / http://127.0.0.1:8000/redoc (Redoc)

🧵 경로 매개변수(동적 라우팅)

  • URL 템플릿과 정규식 기반 매칭 → OpenAPI 스펙으로 타입·범위 검증, 지정된 Python 타입으로 자동 캐스팅
  • 예: @router.get("/users/{user_id}") → user_id: int로 자동 변환 및 유효성 검사

🧪 curl 호출 구성 이해

curl -X 'GET' 'http://127.0.0.1:8000/todo' -H 'accept: application/json'
# -X: 메서드 지정, URL: 엔드포인트, -H: 헤더(원하는 응답 타입)

🧰 프레임워크 비교 (장단점 & 사용 사례)

항목 FastAPI Flask Django

  FastAPI Flask Django
특징 현대적 API-first, 타입 힌트 기반 검증/문서 자동화 마이크로 프레임워크, 유연 배터리 포함 풀스택(ORM/관리자/인증)
성능 매우 높음(ASGI, 비동기) 중간(WSGI, 확장에 따라) 중간(WSGI; ASGI 지원은 점진적)
개발속도 빠름(Pydantic 검증, 자동 스웨거) 빠름(간단한 시작) 복잡하지만 큰 서비스에 구조적
생태계 중간↑(폭발적 성장) 매우 넓음(플러그인 다수) 매우 넓음(ORM, Admin, Auth 강력)
적합도 REST/GraphQL API, 마이크로서비스 소규모 API/PoC/확장 자유 대규모 서비스, 관리 백오피스, 전통적 웹
문서화 /docs, /redoc 자동 제공 확장 필요(Flasgger 등) DRF 사용 시 스키마/문서화 지원
학습곡선 낮음~중간 낮음 중간~높음(DRF 포함 시)

=> 사용 사례

  • FastAPI: 고성능 API, 실시간/비동기 I/O, 데이터 검증 많은 서비스, MSA 게이트웨이
  • Flask: 아주 가벼운 API, 프로토타이핑, 커스텀 구성이 중요한 경우
  • Django(+DRF): 인증/권한/ORM/관리자 콘솔이 필요한 일반 웹 서비스 전반, 대규모 팀

📅 응답 & 헤더

📦 기본 응답 유형

JSON 표준 API 응답 기본 반환(dict) 또는 JSONResponse
HTML 템플릿 렌더링 HTMLResponse, Jinja2 연동
텍스트 단순 메시지 PlainTextResponse
파일 다운로드/정적 FileResponse, StreamingResponse

커스텀 응답

  • 상태 코드/헤더/바디를 명시적으로 제어
  • 예: 비즈니스 규칙에 맞는 에러 포맷, 캐시 전략
from fastapi import FastAPI, Response, status
from fastapi.responses import JSONResponse, HTMLResponse, FileResponse, PlainTextResponse

app = FastAPI()

@app.get("/health")
def health():
    return {"status": "ok"}

@app.get("/hello", response_class=PlainTextResponse)
def hello():
    return "Hello"

@app.get("/page", response_class=HTMLResponse)
def page():
    return "<h1>Hi</h1>"

@app.get("/download")
def download():
    return FileResponse("report.pdf", filename="report.pdf")

@app.get("/custom")
def custom():
    return JSONResponse(
        status_code=status.HTTP_202_ACCEPTED,
        content={"message": "accepted"},
        headers={"Cache-Control": "no-store"}
    )

📨 주요 HTTP 헤더 🔑

  • Content-Type: application/json, text/html; charset=utf-8
  • Authorization: Bearer <token>
  • Cache-Control: no-store, max-age=60
  • Custom Headers: X-Request-Id, X-Rate-Limit-Remaining 등

🏗️ FastAPI 심화 — 구조 & 패턴

권장 디렉터리 예

app/
 ├─ core/        # 설정, 의존성, 보안
 ├─ routers/     # APIRouter 모듈(users.py, posts.py, auth.py)
 ├─ schemas/     # Pydantic 모델
 ├─ services/    # 비즈니스 로직
 ├─ repositories/# 데이터 접근(Repository 패턴)
 ├─ models/      # ORM 모델(SQLAlchemy 등)
 └─ main.py

디자인 패턴 요약

패턴 목적 FastAPI에서의 이점/예

계층형 아키텍처 책임 분리 Router ↔ Service ↔ Repository로 결합도↓
모듈화(단일 책임) 기능별 분리 users, posts, auth 라우터·서비스·스키마 분리
Repository DB 접근 캡슐화 DB 교체 용이, 테스트에서 in-memory 대체 쉬움
싱글턴 인스턴스 1개 보장 설정/클라이언트(예: Redis, Kafka) 공유
팩토리 생성 로직 캡슐화 클라이언트/서비스 구성 시 파라미터별 객체 선택
옵저버(이벤트) 상태 변화 통지 사용자 가입 시 이메일 전송/로그 기록 비동기 처리

Repository 스케치

# app/repositories/todo.py
class TodoRepo:
    def __init__(self, db):
        self.db = db
    def list(self): ...
    def get(self, id: int): ...
    def create(self, dto): ...

서비스는 Repo에 의존하고, 라우터는 서비스에 의존해 테스트가 수월함.


💡 궁금한 것

❗️“Uvicorn이 FastAPI 인스턴스를 가리킨다” ?

  • FastAPI()로 앱 인스턴스를 생성하고, Uvicorn이 module_name:app_object 형태로 해당 객체를 엔트리포인트로 실행한다는 뜻.
    예: uvicorn app.main:app --reload → app/main.py의 app 객체.

🧠 Summary

  • REST: 자원(명사) 중심 + 표현 교환 + 무상태 + 일관 인터페이스
  • URI: 계층 구조 유지(/users/{id}/orders/{id}), 동사 대신 메서드 사용
  • 경로 매개변수: 타입·유효성 자동 검증, 문서화 자동 생성(OpenAPI)
  • 문서화: Swagger /docs(상호작용), Redoc /redoc(정독용)
  • 응답: JSON/HTML/텍스트/파일 + 커스텀(상태·헤더 제어)
  • 헤더: Content-Type, Authorization, Cache-Control 필수 숙지
  • 구조/패턴: Router 분할 + Service/Repository로 책임 분리 → 테스트/확장성 ↑
  • 비교: 실시간/비동기는 FastAPI, 단촐한 실험은 Flask, 풀스택·관리도구는 Django

본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 2기(B-log) 리뷰로 작성 되었습니다.