🕒 약 1분 읽는 데 소요됩니다
– 요청 전후 처리와 앱 생명주기 이벤트를 깔끔하게 다뤄보자
“클라이언트가 요청을 보내기 전, 그리고 서버가 응답을 반환한 후에도 우리는 할 수 있는 일이 많다.”
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. 📌 유의사항 및 팁
- 비동기 함수로 작성하자
startup
과shutdown
함수는 비동기 방식(async def
)으로 정의하는 것이 좋다. 대부분의 리소스 초기화 작업은 네트워크를 사용하기 때문이다. - 다중 미들웨어도 가능하다
여러 개의 미들웨어를 순차적으로 작성할 수 있다. 순서는 작성한 순서대로 적용된다. - 공통 설정은 미들웨어로 빼라
로깅, 헤더 검사, 타이머 등 반복되는 작업은 미들웨어에서 처리하는 것이 깔끔하다. - 예외 처리와 함께 사용하면 더 강력하다
미들웨어 안에서도 try/except를 사용해 예외를 잡아내고, 로깅하는 로직을 넣을 수 있다.
9. 🧾 마무리하며
Middleware와 이벤트는 FastAPI의 숨은 강점이다. 이 기능을 잘 활용하면 코드의 반복을 줄이고, 서비스의 안정성을 크게 높일 수 있다. 특히 실무에서는 로깅, 모니터링, 인증, 캐싱 등 다양한 범용 처리를 미들웨어에서 처리하게 되므로, 꼭 익혀두어야 할 핵심 기능이라 할 수 있다.
기능 | 목적 | 주요 사용 예 |
---|---|---|
Middleware | 요청/응답 전후 공통 작업 처리 | 로깅, 인증 검사, 성능 측정 |
Startup 이벤트 | 서버 실행 시 작업 수행 | DB 연결, 캐시 초기화 |
Shutdown 이벤트 | 서버 종료 시 작업 수행 | 리소스 정리, 로그 마무리 |
FastAPI 공식 문서 : https://fastapi.tiangolo.com/ko/
