# FastAPI 설정 패턴 ## 언제 쓰는가 - FastAPI 프로젝트 초기 구성 시 - Settings + Lifespan + 미들웨어 구조가 필요할 때 ## 핵심 구조 - Pydantic Settings (.env 자동 로드) - Lifespan (startup/shutdown) - CORS + 인증 미들웨어 - 예외 핸들러 ## 코드 예시 ### Settings (Pydantic) ```python class Settings(BaseModel): host: str = "0.0.0.0" port: int = 8000 debug: bool = False database_url: str = "sqlite:///./api.db" allowed_origins: list[str] = ["http://localhost:8000"] rate_limit_per_minute: int = 100 settings = Settings() # .env / .env.local 자동 로드 ``` ### Lifespan (startup/shutdown) ```python @asynccontextmanager async def lifespan(app: FastAPI): # Startup await init_database() yield # Shutdown await cleanup() app = FastAPI(lifespan=lifespan) ``` ### 미들웨어 (CORS + 인증) ```python app.add_middleware(CORSMiddleware, allow_origins=settings.allowed_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"]) @app.middleware("http") async def auth_middleware(request: Request, call_next): if request.url.path in PUBLIC_PATHS: return await call_next(request) api_key = request.headers.get("Authorization", "").removeprefix("Bearer ") if not api_key: api_key = request.headers.get("X-API-Key", "") if not validate(api_key): return JSONResponse(status_code=401, content={"error": "Unauthorized"}) return await call_next(request) ``` ### 예외 핸들러 ```python @app.exception_handler(HTTPException) async def http_exception_handler(request, exc): return JSONResponse(status_code=exc.status_code, content={"error": {"message": exc.detail, "code": exc.status_code}}) @app.exception_handler(Exception) async def general_exception_handler(request, exc): return JSONResponse(status_code=500, content={"error": {"message": "Internal server error"}}) ``` ## 주의사항 - `@app.on_event("startup")` 대신 `lifespan` 사용 (공식 권장) - API Key는 쿼리스트링이 아닌 헤더에서만 추출 (로그 노출 방지) - 인메모리 Rate Limiter는 단일 인스턴스만 유효 - 에러 응답에 내부 스택트레이스 노출 금지 ## 재사용 방법 - Settings + Lifespan + 미들웨어 구조 그대로 복사 - Settings 필드만 프로젝트에 맞게 추가/변경 - 라우터는 `app.include_router()`로 분리 등록