⚙️ FastAPI의 중간처리(Middleware)와 이벤트 시스템

🕒 약 1분 읽는 데 소요됩니다

이전 글 보기(FastAPI에서의 예외 처리)

– 요청 전후 처리와 앱 생명주기 이벤트를 깔끔하게 다뤄보자

“클라이언트가 요청을 보내기 전, 그리고 서버가 응답을 반환한 후에도 우리는 할 수 있는 일이 많다.”

FastAPI의 Middleware와 이벤트 시스템은 바로 이 시점을 잡아내어 로깅, 인증, 성능 측정, 리소스 관리 등 다양한 작업을 처리할 수 있도록 해준다.


1. 📦 Middleware란?

Middleware는 클라이언트 요청과 API 엔드포인트 사이에 끼어드는 중간 레이어이다.
즉, 사용자가 API를 호출할 때 이 요청은 미들웨어 → 실제 라우터 → 미들웨어 → 응답 반환의 흐름으로 동작한다.

✅ 언제 사용하나?

  • 모든 요청에 대해 로깅을 남기고 싶을 때
  • 요청 헤더를 검사해 인증 여부를 확인할 때
  • API 사용량 측정 또는 시간 측정을 할 때
  • CORS, GZip 압축, 세션 처리 등 범용 설정을 넣고 싶을 때

2. 🛠 미들웨어 작성법

FastAPI에서는 @app.middleware("http") 데코레이터를 이용해 아주 쉽게 미들웨어를 작성할 수 있다.

기본 구조 예시

from fastapi import FastAPI, Request
import time

app = FastAPI()

@app.middleware("http")
async def log_request_time(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    print(f"요청 경로: {request.url.path} / 처리 시간: {process_time:.4f}초")
    return response
  • request: 사용자의 요청 객체이다.
  • call_next(request): 실제 API 라우터로 요청을 전달하는 함수이다.
  • 미들웨어는 request를 받아서 응답 전후로 원하는 작업을 수행할 수 있다.

이 코드를 실행하면 모든 요청의 처리 시간과 경로가 콘솔에 출력된다. 성능 모니터링에 유용하다.


3. 🔄 미들웨어 동작 흐름

클라이언트 요청
       ↓
미들웨어 시작
       ↓
실제 API 처리 (@app.get 등)
       ↓
미들웨어 종료
       ↓
클라이언트 응답

중요한 건 미들웨어는 요청과 응답 모두에 개입할 수 있다는 점이다. 이중 필터 역할을 한다고 생각해보자.


4. ✨ 미들웨어 활용 예제: 헤더 필터링

@app.middleware("http")
async def check_api_key(request: Request, call_next):
    if "x-api-key" not in request.headers:
        from fastapi.responses import JSONResponse
        return JSONResponse(status_code=403, content={"detail": "API 키가 없습니다."})
    
    return await call_next(request)
  • 헤더에 "x-api-key"가 없으면 바로 403 Forbidden 에러를 반환한다.
  • 이런 방식으로 간단한 인증 또는 접근 제어를 구현할 수 있다.

5. ⚡ FastAPI 앱 실행 전후 이벤트 처리

웹 애플리케이션은 단순히 요청을 처리하는 것뿐만 아니라, 서버가 시작되거나 종료될 때 필요한 작업을 수행해야 할 때가 많다. 예를 들어:

  • DB 연결
  • 리소스 초기화
  • 로그 시작
  • 캐시 세팅

이럴 때 사용하는 게 바로 startup/shutdown 이벤트이다.


6. 🚀 startup 이벤트: 앱이 실행될 때 실행

@app.on_event("startup")
async def startup_event():
    print("FastAPI 애플리케이션이 시작되었습니다.")
  • 서버가 실행되자마자 한 번 호출된다.
  • 비동기 작업도 가능하므로, 데이터베이스 연결 같은 작업을 수행하는 데 적합하다.

예: 비동기 DB 연결

from databases import Database

database = Database("sqlite+aiosqlite:///./test.db")

@app.on_event("startup")
async def connect_db():
    await database.connect()

@app.on_event("shutdown")
async def disconnect_db():
    await database.disconnect()

7. 📴 shutdown 이벤트: 앱이 종료될 때 실행

@app.on_event("shutdown")
async def shutdown_event():
    print("FastAPI 애플리케이션이 종료됩니다.")
  • 서버가 종료되기 직전에 실행된다.
  • 열려 있는 커넥션을 닫거나 파일을 저장하거나, 로그를 마무리하는 작업을 수행하면 된다.

8. 📌 유의사항 및 팁

  1. 비동기 함수로 작성하자
    startupshutdown 함수는 비동기 방식(async def)으로 정의하는 것이 좋다. 대부분의 리소스 초기화 작업은 네트워크를 사용하기 때문이다.
  2. 다중 미들웨어도 가능하다
    여러 개의 미들웨어를 순차적으로 작성할 수 있다. 순서는 작성한 순서대로 적용된다.
  3. 공통 설정은 미들웨어로 빼라
    로깅, 헤더 검사, 타이머 등 반복되는 작업은 미들웨어에서 처리하는 것이 깔끔하다.
  4. 예외 처리와 함께 사용하면 더 강력하다
    미들웨어 안에서도 try/except를 사용해 예외를 잡아내고, 로깅하는 로직을 넣을 수 있다.

9. 🧾 마무리하며

Middleware와 이벤트는 FastAPI의 숨은 강점이다. 이 기능을 잘 활용하면 코드의 반복을 줄이고, 서비스의 안정성을 크게 높일 수 있다. 특히 실무에서는 로깅, 모니터링, 인증, 캐싱 등 다양한 범용 처리를 미들웨어에서 처리하게 되므로, 꼭 익혀두어야 할 핵심 기능이라 할 수 있다.

기능목적주요 사용 예
Middleware요청/응답 전후 공통 작업 처리로깅, 인증 검사, 성능 측정
Startup 이벤트서버 실행 시 작업 수행DB 연결, 캐시 초기화
Shutdown 이벤트서버 종료 시 작업 수행리소스 정리, 로그 마무리

FastAPI 공식 문서 : https://fastapi.tiangolo.com/ko/

fastapi-logo,fastapi-개발-환경-설정, fastapi-앱-만들기, fastapi-라우팅, fastapi-request-response, fastapi-예외-처리, fastapi-middleware-이벤트-시스템