FastAPI 서버개발, FastAPI Middleware 사용하기

오늘날 웹 애플리케이션 개발에서는 API 서버가 매우 중요한 역할을 하며, FastAPI는 그러한 API 서버를 빠르게 구축할 수 있는 효율적인 프레임워크입니다. 이번 강좌에서는 FastAPI의 기본적인 개념을 설명하고, Middleware의 개념과 사용법에 대해 심층적으로 알아보겠습니다.

1. FastAPI란 무엇인가?

FastAPI는 Python으로 개발된 현대적인 웹 프레임워크로, RESTful API를 빠르게 구축하는 데 초점을 맞추고 있습니다. FastAPI는 다음과 같은 주요 기능을 제공합니다:

  • 빠른 성능: Starlette와 Pydantic을 기반으로 하여 매우 빠른 처리 속도를 자랑합니다.
  • 자동화된 문서 생성: OpenAPI 및 JSON Schema를 사용하여 Swagger UI와 ReDoc 같은 문서를 자동으로 생성합니다.
  • 유효성 검사: Pydantic을 사용하여 데이터 유효성을 검사하고 문서화합니다.
  • 비동기 지원: 비동기 프로그래밍을 지원하여 높은 성능을 유지할 수 있습니다.

2. Middleware란 무엇인가?

Middleware는 요청(request)과 응답(response) 사이에서 작업을 수행하는 코드를 의미합니다. 기본적으로 웹 프레임워크의 ‘층'(layer) 사이에서 실행되며, 다음과 같은 작업을 수행할 수 있습니다:

  • 요청/응답의 로깅
  • 인증 및 권한 부여
  • 처리 시간 측정
  • 요청 데이터 변형
  • CORS 처리

FastAPI에서는 Middleware를 사용하여 이러한 작업을 효율적으로 처리할 수 있습니다. FastAPI는 Starlette 기반으로 구축되어 있으므로 Starlette의 Middleware를 그대로 사용할 수 있습니다.

3. FastAPI Middleware 기본 사용법

3.1 FastAPI 설치하기

먼저, FastAPI와 Uvicorn을 설치합니다. Uvicorn은 FastAPI 애플리케이션을 실행하기 위한 ASGI 서버입니다.

pip install fastapi uvicorn

3.2 기본 FastAPI 애플리케이션 만들기

기본 FastAPI 애플리케이션을 만들어 보겠습니다.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

이 코드는 기본적인 FastAPI 애플리케이션을 정의합니다. 웹 브라우저에서 http://127.0.0.1:8000/에 접근하면 {“message”: “Hello, FastAPI!”}라는 JSON 응답을 볼 수 있습니다.

3.3 Middleware 추가하기

이제 애플리케이션에 Middleware를 추가해 보겠습니다. 다음은 요청과 응답을 로그로 기록하는 Middleware의 예입니다.

from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
import time

class LoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start_time = time.time()
        
        # 요청 로그
        print(f"Request: {request.method} {request.url}")
        
        # 다음 미들웨어 또는 라우트를 호출하고 응답 받기
        response = await call_next(request)

        # 응답 로그
        duration = time.time() - start_time
        print(f"Response: {response.status_code} | Duration: {duration:.2f} seconds")

        return response

app = FastAPI()

# Middleware 등록
app.add_middleware(LoggingMiddleware)

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

위의 코드에서 우리는 LoggingMiddleware 클래스를 정의하여 요청과 응답을 로그로 기록합니다. dispatch 메서드 내에서 요청을 로그로 기록하고, call_next 함수를 호출하여 다음 미들웨어 또는 최종 라우트로 요청을 전달합니다. 마지막으로 응답을 받아 로그를 기록하고 클라이언트에게 반환합니다.

4. 여러 Middleware 사용하기

FastAPI에서 여러 가지 Middleware를 함께 사용할 수 있습니다. 예를 들어, 다음과 같이 CORS(Cross-Origin Resource Sharing) Middleware와 Logging Middleware를 함께 사용할 수 있습니다.

from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
import time

class LoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start_time = time.time()
        print(f"Request: {request.method} {request.url}")
        response = await call_next(request)
        duration = time.time() - start_time
        print(f"Response: {response.status_code} | Duration: {duration:.2f} seconds")
        return response

app = FastAPI()

# CORS Middleware 등록
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 모든 오리진 허용
    allow_credentials=True,
    allow_methods=["*"],  # 모든 HTTP 메서드 허용
    allow_headers=["*"],  # 모든 헤더 허용
)

# Logging Middleware 등록
app.add_middleware(LoggingMiddleware)

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

5. 실전 예제: 사용자 인증을 위한 Middleware 구현

이번에는 기본적인 사용자 인증을 위한 Middleware를 만들어 보고, 이를 사용하여 API에 접근할 수 있는 사용자 인증을 구현해 보겠습니다.

from fastapi import FastAPI, Depends, HTTPException, status
from starlette.middleware.base import BaseHTTPMiddleware

class AuthMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        token = request.headers.get("Authorization")
        
        # 기본적인 토큰 검증
        if token != "Bearer mysecrettoken":
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized")
        
        response = await call_next(request)
        return response

app = FastAPI()

# 인증 Middleware 등록
app.add_middleware(AuthMiddleware)

@app.get("/protected")
async def protected_route():
    return {"message": "You are authorized!"}

위의 코드는 간단한 인증 Middleware를 구현한 것입니다. 요청의 헤더에 Authorization 필드가 있는지를 확인하고, 유효한 토큰이 아닐 경우 401 Unauthorized 에러를 반환합니다. 이를 통해 /protected 엔드포인트에 접근할 때 인증이 필요하게 됩니다.

6. 결론

FastAPI는 매우 강력한 웹 프레임워크로, Middleware를 통해 다양한 기능을 추가할 수 있습니다. 본 강좌에서는 Middleware의 기본 개념과 구현 방법, 그리고 여러 가지 사용 사례를 다루어 보았습니다. 이를 통해 API 서버를 더욱 유연하고 강력하게 만들 수 있습니다.

FastAPI와 Middleware에 대해 더 배우고 싶다면 공식 문서와 다양한 예제를 참고하시기 바랍니다. 짧은 코드로 강력한 웹 애플리케이션을 구축할 수 있는 FastAPI의 매력을 경험해 보세요!