Skip to Content
Python / FastAPI

Python & FastAPI

FastAPI는 파이썬의 타입 힌트를 그대로 API 계약으로 끌어올린 프레임워크다. 같은 타입 선언 하나로 검증·직렬화·문서화가 동시에 해결된다. Spring과 비교하며 비동기 API 설계의 핵심을 정리한다.
1

FastAPI를 쓰는 이유

FastAPI는 Starlette(ASGI)와 Pydantic 위에 세워진 현대적 파이썬 웹 프레임워크다. 타입 힌트를 선언하면 그것이 곧 입력 검증, 응답 직렬화, 자동 문서(OpenAPI)로 이어진다.

타입 힌트 = 계약

함수 시그니처에 타입을 적으면 FastAPI가 요청 파싱·검증을 자동 처리한다. 별도의 검증 코드를 거의 작성하지 않는다.

자동 문서화

선언된 타입을 기반으로 /docs(Swagger UI)와 /redoc이 자동 생성된다. 코드와 문서가 어긋날 일이 없다.

관점Spring BootFastAPI
언어 / 런타임Java / JVMPython / ASGI
검증Bean Validation (@Valid)Pydantic (타입 힌트)
DI컨테이너 기반 Bean 주입Depends 함수 주입
비동기WebFlux(별도) / 가상 스레드async/await 1급 지원
문서springdoc 등 추가 설정기본 내장 (OpenAPI)
2

경로 동작과 타입 힌트

경로 동작 함수(path operation)는 데코레이터로 메서드·경로를 선언하고, 파라미터 타입을 힌트로 적는다. 경로 변수·쿼리 파라미터·본문이 타입만으로 구분된다.

main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int, verbose: bool = False):
    # user_id → 경로 변수(int로 자동 변환·검증)
    # verbose → 쿼리 파라미터(기본값 있으면 선택)
    return {"id": user_id, "verbose": verbose}
  • 경로 변수: 경로에 {user_id}로 선언하고 함수 인자 타입으로 받는다. int면 정수가 아닌 값에 자동 422 응답.
  • 쿼리 파라미터: 경로에 없는 인자는 쿼리로 해석된다. 기본값이 있으면 선택, 없으면 필수다.
  • 요청 본문: Pydantic 모델 타입으로 받으면 JSON 본문으로 해석된다 (다음 섹션).
3

Pydantic 모델 검증

요청·응답 본문은 Pydantic 모델로 정의한다. 모델은 검증 규칙이자 직렬화 스키마이며, 그대로 OpenAPI 문서에 반영된다. Spring의 DTO + Bean Validation을 하나로 합친 셈이다.

schemas.py
from pydantic import BaseModel, EmailStr, Field

class CreateUser(BaseModel):
    name: str = Field(min_length=1, max_length=50)
    email: EmailStr
    age: int = Field(ge=0, le=150)

class UserResponse(BaseModel):
    id: int
    name: str
    email: EmailStr

@app.post("/users", response_model=UserResponse, status_code=201)
def create_user(body: CreateUser):
    # body는 이미 검증 완료 상태 — 깨진 입력은 여기 도달 전 422
    return service.create(body)

response_model의 역할

응답을 UserResponse로 필터링하면, 내부 모델에 비밀번호 같은 필드가 있어도 응답에서 자동 제외된다. 과다 노출을 막는다.

Field 제약

min_length, ge(이상), le(이하) 등으로 필드 단위 규칙을 선언한다. 위반 시 어떤 필드가 왜 틀렸는지 상세 응답이 나간다.

단일 원천

하나의 Pydantic 모델이 ‘검증 + 직렬화 + 문서’ 세 가지를 동시에 책임진다. 세 곳이 따로 노는 불일치 문제가 구조적으로 사라진다.

4

의존성 주입 (Depends)

FastAPI의 DI는 Depends 함수 하나로 동작한다. DB 세션·인증 사용자·공통 파라미터 등을 함수로 정의하고 주입받는다. 호출 그래프가 곧 의존성 그래프다.

deps.py
from fastapi import Depends, HTTPException

def get_db():
    db = SessionLocal()
    try:
        yield db          # 요청 동안 세션 제공
    finally:
        db.close()        # 응답 후 정리(teardown)

def get_current_user(token: str = Depends(oauth2_scheme),
                     db = Depends(get_db)):
    user = decode(token, db)
    if user is None:
        raise HTTPException(status_code=401, detail="인증 실패")
    return user

@app.get("/me")
def read_me(user = Depends(get_current_user)):
    return user
  • yield 의존성: yield 앞은 준비, 뒤는 정리. DB 세션처럼 열고 닫아야 하는 자원에 적합하다.
  • 중첩 주입: 의존성이 또 다른 의존성을 받을 수 있다. FastAPI가 그래프 순서대로 해결한다.
  • 테스트 용이성: app.dependency_overrides로 의존성을 가짜 구현으로 교체해 테스트한다(6번 참고).
5

동기 vs 비동기

FastAPI는 defasync def를 모두 지원한다. 선택 기준은 ‘그 안에서 무엇을 기다리느냐’다. 잘못 고르면 오히려 성능이 나빠진다.

async def — I/O 대기 위주

비동기 DB 드라이버·HTTP 호출 등 await 가능한 I/O를 기다린다면 async def로 작성한다. 대기 동안 이벤트 루프가 다른 요청을 처리한다.

def — 블로킹/CPU 작업

동기 라이브러리나 CPU 연산은 일반 def로 둔다. FastAPI가 이를 별도 스레드풀에서 실행해 이벤트 루프를 막지 않는다.

가장 흔한 실수

async def 안에서 블로킹 호출(동기 DB 드라이버, time.sleep)을 하면 이벤트 루프 전체가 멈춰 모든 요청이 느려진다. 비동기 함수 안에서는 반드시 await 가능한 비동기 클라이언트를 쓴다.

6

테스트 전략

FastAPI는 TestClient로 실제 서버 없이 앱을 인메모리로 호출한다. 여기에 의존성 오버라이드를 더하면 DB·인증을 가짜로 갈아끼워 빠르게 검증할 수 있다.

test_users.py
from fastapi.testclient import TestClient
from main import app, get_db

def override_get_db():
    yield FakeSession()   # 테스트용 가짜 세션

app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)

def test_create_user():
    res = client.post("/users", json={
        "name": "지연", "email": "a@b.com", "age": 30
    })
    assert res.status_code == 201
    assert res.json()["email"] == "a@b.com"

def test_validation_error():
    res = client.post("/users", json={"name": ""})
    assert res.status_code == 422   # Pydantic 검증 실패

dependency_overrides

실제 DB·외부 API 의존성을 테스트용 구현으로 교체한다. Spring의 @MockBean과 같은 발상이다.

422 검증 테스트

잘못된 입력이 Pydantic 단계에서 막히는지(422) 확인하는 테스트는, 검증 규칙을 지키는 안전망이 된다.

FastAPI의 힘은 ‘타입 힌트 하나가 검증·직렬화·문서를 동시에 책임진다’는 데 있다.
타입으로 계약을 선언하고, 의존성을 함수로 주입하고, I/O에 맞게 async를 골라라.