[2026] FastAPI 완벽 가이드 | Python·REST API·Async·Pydantic·자동 문서화

[2026] FastAPI 완벽 가이드 | Python·REST API·Async·Pydantic·자동 문서화

이 글의 핵심

FastAPI로 고성능 API를 구축하는 완벽 가이드입니다. 설치부터 라우팅, Pydantic, 비동기, 의존성 주입, 인증, 자동 문서화까지 실전 예제로 정리했습니다.

실무 경험 공유: Flask 기반 API를 FastAPI로 마이그레이션하면서, 응답 속도를 3배 향상시키고 자동 문서화로 개발 시간을 50% 단축한 경험을 공유합니다.

들어가며: “Flask가 느려요”

실무 문제 시나리오

시나리오 1: API가 느려요
Flask는 동기 방식입니다. FastAPI는 비동기로 3배 빠릅니다. 시나리오 2: 타입 검증이 번거로워요
수동으로 검증해야 합니다. FastAPI는 Pydantic으로 자동 검증합니다. 시나리오 3: API 문서를 따로 작성해야 해요
Swagger를 수동으로 작성합니다. FastAPI는 자동 생성합니다.

1. FastAPI란?

핵심 특징

FastAPI는 현대적이고 빠른 Python 웹 프레임워크입니다. 주요 장점:

  • 빠른 성능: Node.js, Go와 비슷
  • 자동 문서화: OpenAPI/Swagger 자동 생성
  • 타입 안전성: Pydantic 기반
  • 비동기: async/await 지원
  • 쉬운 학습: 직관적인 API 성능 비교:
  • Flask: 1,000 req/sec
  • Django: 800 req/sec
  • FastAPI: 3,000 req/sec

2. 설치 및 시작

설치

pip install fastapi uvicorn[standard]

첫 번째 API

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
    return {"message": "Hello World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}

실행

uvicorn main:app --reload

브라우저에서:

  • API: http://localhost:8000
  • 자동 문서: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

3. Pydantic Models

요청 Body

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from pydantic import BaseModel, EmailStr, Field
class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    email: EmailStr
    age: int = Field(..., ge=0, le=150)
    is_active: bool = True
@app.post("/users")
async def create_user(user: User):
    return {"user": user, "id": 123}

응답 Model

다음은 python를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    
    class Config:
        from_attributes = True
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    return {
        "id": user_id,
        "name": "John",
        "email": "john@example.com",
        "password": "secret",  # 응답에서 제외됨
    }

4. 의존성 주입

기본 의존성

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from fastapi import Depends
async def get_db():
    db = Database()
    try:
        yield db
    finally:
        await db.close()
@app.get("/users")
async def get_users(db = Depends(get_db)):
    return await db.fetch_all("SELECT * FROM users")

인증 의존성

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = decode_token(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
        )
    return user
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_user)):
    return current_user

5. 비동기 처리

비동기 DB 쿼리

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from databases import Database
database = Database("postgresql://user:pass@localhost/db")
@app.on_event("startup")
async def startup():
    await database.connect()
@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()
@app.get("/users")
async def get_users():
    query = "SELECT * FROM users"
    return await database.fetch_all(query)

비동기 HTTP 요청

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

import httpx
@app.get("/external")
async def fetch_external():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/data")
        return response.json()

6. 인증

JWT 인증

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

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=[bcrypt], deprecated="auto")
def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(status_code=400, detail="Incorrect credentials")
    
    access_token = create_access_token(data={"sub": user.email})
    return {"access_token": access_token, "token_type": "bearer"}

7. 파일 업로드

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from fastapi import File, UploadFile
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    contents = await file.read()
    
    # 파일 저장
    with open(f"uploads/{file.filename}", "wb") as f:
        f.write(contents)
    
    return {
        "filename": file.filename,
        "content_type": file.content_type,
        "size": len(contents),
    }
@app.post("/upload-multiple")
async def upload_multiple(files: list[UploadFile] = File(...)):
    return [
        {"filename": file.filename, "size": len(await file.read())}
        for file in files
    ]

8. 백그라운드 작업

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 비동기 처리를 통해 효율적으로 작업을 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from fastapi import BackgroundTasks
def send_email(email: str, message: str):
    # 이메일 전송 로직
    print(f"Sending email to {email}: {message}")
@app.post("/send-notification")
async def send_notification(
    email: str,
    background_tasks: BackgroundTasks,
):
    background_tasks.add_task(send_email, email, "Welcome!")
    return {"message": "Notification sent in the background"}

9. CORS

아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=[http://localhost:3000],
    allow_credentials=True,
    allow_methods=[*],
    allow_headers=[*],
)

10. 실전 예제: Todo API

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from typing import List
app = FastAPI()
class TodoCreate(BaseModel):
    title: str
    description: str | None = None
class Todo(BaseModel):
    id: int
    title: str
    description: str | None
    completed: bool = False
todos: List[Todo] = []
@app.get("/todos", response_model=List[Todo])
async def get_todos():
    return todos
@app.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: int):
    todo = next((t for t in todos if t.id == todo_id), None)
    if not todo:
        raise HTTPException(status_code=404, detail="Todo not found")
    return todo
@app.post("/todos", response_model=Todo, status_code=201)
async def create_todo(todo: TodoCreate):
    new_todo = Todo(id=len(todos) + 1, **todo.dict())
    todos.append(new_todo)
    return new_todo
@app.put("/todos/{todo_id}", response_model=Todo)
async def update_todo(todo_id: int, todo: TodoCreate):
    existing = next((t for t in todos if t.id == todo_id), None)
    if not existing:
        raise HTTPException(status_code=404, detail="Todo not found")
    
    existing.title = todo.title
    existing.description = todo.description
    return existing
@app.delete("/todos/{todo_id}")
async def delete_todo(todo_id: int):
    global todos
    todos = [t for t in todos if t.id != todo_id]
    return {"message": "Todo deleted"}

11. 배포

Docker

아래 코드는 dockerfile를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

FROM python:3.11-slim
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"]

requirements.txt

아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

fastapi==0.110.0
uvicorn[standard]==0.27.0
pydantic==2.6.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4

정리 및 체크리스트

핵심 요약

  • FastAPI: 현대적이고 빠른 Python 프레임워크
  • 자동 문서화: OpenAPI/Swagger 자동 생성
  • 타입 안전성: Pydantic 기반
  • 비동기: async/await 지원
  • 의존성 주입: 깔끔한 코드 구조

구현 체크리스트

  • FastAPI 프로젝트 생성
  • Pydantic Models 정의
  • 라우트 구현
  • 의존성 주입 설정
  • 인증 구현
  • 테스트 작성
  • 배포

같이 보면 좋은 글

  • NestJS 완벽 가이드
  • PostgreSQL 고급 가이드
  • Redis 고급 가이드

이 글에서 다루는 키워드

FastAPI, Python, REST API, Async, Pydantic, Backend, OpenAPI

자주 묻는 질문 (FAQ)

Q. FastAPI vs Flask, 어떤 게 나은가요?

A. FastAPI가 더 빠르고 현대적입니다. 자동 문서화와 타입 검증이 내장되어 있습니다. 새 프로젝트는 FastAPI를 권장합니다.

Q. 동기 함수도 사용할 수 있나요?

A. 네, async def 대신 def를 사용하면 됩니다. 하지만 비동기를 권장합니다.

Q. Django와 비교하면?

A. FastAPI는 API 전용이고 가볍습니다. Django는 풀스택 프레임워크입니다. API만 필요하면 FastAPI가 적합합니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, Microsoft, Uber 등 많은 기업에서 프로덕션 환경에서 사용하고 있습니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3