Study/fastapi

fastapi의 FastAPI() 메소드 사용법 정리

bluebamus 2025. 2. 16.

1. 애플리케이션 생성

   1) FastAPI 인스턴스 생성

app = FastAPI(
    title="My API",                  # API 제목
    description="API 설명",           # API 설명
    version="1.0.0",                # API 버전
    docs_url="/docs",               # Swagger UI 경로
    redoc_url="/redoc",            # ReDoc 경로
    openapi_url="/openapi.json",   # OpenAPI 스키마 경로
    debug=False                     # 디버그 모드 설정
)

 

      1. 매개변수 설명:

         - title: API의 이름을 지정합니다. OpenAPI 문서에 표시된다.
         - description: API에 대한 자세한 설명을 제공한다.
         - version: API의 버전을 지정한다.
         - docs_url: Swagger UI의 접근 경로를 설정합니다. None으로 설정하면 비활성화된다.
         - redoc_url: ReDoc 문서의 접근 경로를 설정합니다. None으로 설정하면 비활성화된다.
         - openapi_url: OpenAPI 스키마 JSON 파일의 경로를 설정한다.
         - debug: 디버그 모드를 활성화/비활성화한다.

파라미터 기본값 설명
title "FastAPI" OpenAPI 문서 제목 (예: title="My API")
description "" API 설명 (OpenAPI 문서에 표시)
version "0.1.0" API 버전 (예: version="1.0.0")
docs_url "/docs" Swagger UI 문서 URL (비활성화: docs_url=None)
redoc_url "/redoc" ReDoc 문서 URL (비활성화: redoc_url=None)
openapi_url "/openapi.json" OpenAPI 스키마 URL (비활성화: openapi_url=None)
debug FALSE 디버그 모드 활성화 (자세한 에러 메시지 표시)
dependencies None 전역 종속성 (예: dependencies=[Depend(common_dependency)])

 

2. 라우팅 메소드

   1) HTTP 메소드 데코레이터

      - 라우트를 간편하게 등록할 수 있도록 아래와 같은 데코레이터들을 제공합니다. 이들 데코레이터는 내부적으로 add_api_route()를 호출한다.

 

      1. @app.get(path, …) : GET 요청 처리

      2. @app.post(path, …) : POST 요청 처리

      3. @app.put(path, …) : PUT 요청 처리

      4. @app.delete(path, …) : DELETE 요청 처리

      5. @app.patch(path, …) : PATCH 요청 처리

      6. @app.options(path, …) : OPTIONS 요청 처리

      7. @app.head(path, …) : HEAD 요청 처리

      8. @app.trace(path, …) : TRACE 요청 처리

@app.get("/items/{item_id}")
@app.post("/items/")
@app.put("/items/{item_id}")
@app.delete("/items/{item_id}")
@app.patch("/items/{item_id}")
@app.options("/items/{item_id}")
@app.head("/items/{item_id}")
@app.trace("/items/{item_id}")

 

      1. 매개변수 설명:

         - path: 엔드포인트 경로
         - response_model: 응답 데이터의 Pydantic 모델
         - status_code: HTTP 상태 코드
         - tags: API 문서화를 위한 태그
         - summary: API 엔드포인트 요약
         - description: 자세한 설명
         - response_description: 응답에 대한 설명
         - deprecated: 해당 엔드포인트의 사용 중단 여부

파라미터 타입 설명
path str URL 경로 (기본값: 데코레이터가 적용된 함수의 경로)
status_code int 응답 상태 코드 (기본값: GET=200, POST=201, DELETE=204 등)
tags List[str] OpenAPI 문서에서 그룹화할 태그 (예: tags=["users"])
summary str API 요약 설명
description str API 상세 설명
response_model Type[BaseModel] 응답 모델 (Pydantic 모델)
deprecated bool API 사용 중단 표시 (OpenAPI 문서에서 강조)
dependencies List[Depends] 라우트별 종속성 (예: dependencies=[Depend(auth)])
response_class Response 기본 응답 클래스 (예: JSONResponse, HTMLResponse)
responses Dict OpenAPI 문서에 추가할 응답 예시 (예: {404: {"description": ...}})
include_in_schema bool OpenAPI 스키마 포함 여부 (기본값: True)
from fastapi import FastAPI, status
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float

app = FastAPI(title="My API", description="API 예제", version="1.0.0")

@app.get("/items/{item_id}", response_model=Item, status_code=status.HTTP_200_OK, tags=["items"],
         summary="아이템 조회", description="주어진 item_id에 해당하는 아이템 정보를 반환합니다.")
async def read_item(item_id: int):
    # 실제 데이터 조회 로직
    return {"name": "Sample Item", "price": 42.0}
@app.get(
    "/items/{item_id}",
    response_model=Item,
    status_code=200,
    tags=["items"],
    summary="아이템 조회",
    description="ID를 기반으로 특정 아이템을 조회합니다.",
    response_description="요청한 아이템 정보"
)
async def read_item(item_id: int):
    return {"item_id": item_id}

 

      2. 경로 파라미터 & 쿼리 파라미터

         - 라우트 함수에서 사용되는 파라미터 (예: @app.get("/items/{item_id}")).

파라미터 유형 예시 설명
경로 파라미터 item_id: int URL 경로에서 추출 ({item_id})
쿼리 파라미터 skip: int = 0 URL 쿼리 문자열에서 추출
요청 바디 item: Item (Pydantic 모델) POST/PUT 요청의 본문 데이터
Form 데이터 username: str = Form(...) HTML Form 데이터 수신
파일 업로드 file: UploadFile = File(...) 파일 업로드 처리

 

   2) add_api_route() 메소드

      - add_api_route()는 모든 HTTP 메소드 데코레이터의 기반이 되는 메소드이다. 직접 호출하여 라우트를 등록할 수도 있다.

 

      - 파라미터

         - path (str): 라우트 경로

         - endpoint (Callable): 요청 시 호출되는 함수(핸들러)

         - methods (Optional[List[str]]): 허용할 HTTP 메소드 목록 (예: ["GET"])

         - response_model (Optional[Type]): 응답으로 반환할 데이터의 Pydantic 모델

            - 자동으로 데이터 검증, 직렬화, OpenAPI 문서 생성에 사용된다.

         - status_code (Optional[int]): 기본 응답 상태 코드

         - tags (Optional[List[str]]): API 문서에서 그룹핑할 태그

         - summary (Optional[str]): 간략한 요약

         - description (Optional[str]): 상세 설명 (docstring 형식도 지원)

         - response_description (str): 응답에 대한 설명 (기본값: "Successful Response")

         - responses (Optional[Dict[Union[int, str], Dict[str, Any]]]): 추가 응답 설명

         - deprecated (bool): 해당 엔드포인트가 더 이상 사용되지 않음을 명시할 때

         - name (Optional[str]): 내부적으로 사용할 이름 (OpenAPI 스키마에 반영)

         - include_in_schema (bool): OpenAPI 문서에 포함할지 여부 (기본값: True)

         - response_class (Optional[Type[Response]]): 응답 클래스를 지정 (예: JSONResponse, HTMLResponse)

         - dependencies (Optional[Sequence[Depends]]): 엔드포인트 전반에 적용할 의존성 목록

         - callbacks (Optional[List[APIRoute]]): 콜백 경로 등

 

         - 예시:

def my_endpoint():
    return {"message": "Hello"}

app.add_api_route(
    path="/hello",
    endpoint=my_endpoint,
    methods=["GET"],
    response_model=dict,
    status_code=200,
    tags=["example"],
    summary="Hello Endpoint",
    description="간단한 인사말을 반환합니다.",
)

 

   3) include_router() 메소드

      - 복잡한 애플리케이션에서는 여러 개의 라우터(APIRouter)를 분리하여 관리할 수 있다.
      - include_router()를 사용하면 외부에서 정의된 라우터를 현재 애플리케이션에 포함시킬 수 있다.

      - 주요 파라미터

         - router (APIRouter): 포함할 라우터 객체
         - prefix (Optional[str]): 라우터 내 모든 경로 앞에 붙일 공통 경로
         - tags (Optional[List[str]]): 해당 라우터에 적용할 태그 목록
         - dependencies (Optional[Sequence[Depends]]): 라우터 전역에 적용할 의존성 목록
         - responses (Optional[Dict]): 라우터에 적용할 응답 설정

파라미터 설명
router 포함할 APIRouter 객체
prefix 라우터 경로에 추가할 접두사 (예: prefix="/api")
tags 라우터의 모든 경로에 적용될 태그 (예: tags=["auth"])
dependencies 라우터 전체에 적용될 종속성
responses 라우터의 모든 경로에 적용될 공통 응답
from fastapi import APIRouter

router = APIRouter()

@router.get("/users")
async def get_users():
    return [{"username": "alice"}, {"username": "bob"}]

app.include_router(router, prefix="/api", tags=["users"])

 

   4) WebSocket 라우트 등록

      1. @app.websocket() 데코레이터 사용하기

         - 주요 특징

            - 직관적 정의: 일반적인 HTTP 엔드포인트와 유사하게 데코레이터를 사용해 WebSocket 라우트를 정의할 수 있다.
            - 비동기 처리: WebSocket 핸들러는 반드시 비동기 함수(async def)로 작성해야 하며, 연결 수락, 메시지 송수신 등 모든 작업이 비동기적으로 이루어진다.

 

         - 동작 과정

             - 연결 수락:

                - await websocket.accept()를 호출하여 클라이언트의 연결 요청을 승인한다.

             - 메시지 송수신:

                - 무한 루프 내에서 receive_text() (또는 receive_bytes())를 통해 데이터를 기다리고, 수신한 데이터를 send_text()로 클라이언트에 응답한다.

             - 예외 처리:

                - 클라이언트가 연결을 끊으면 WebSocketDisconnect 예외가 발생하므로 이를 캐치하여 종료 처리한다.

 

         - 기본 코드 예제

from fastapi import FastAPI, WebSocket
from starlette.websockets import WebSocketDisconnect

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    # 클라이언트의 연결 요청을 수락
    await websocket.accept()
    try:
        while True:
            # 클라이언트로부터 텍스트 메시지 수신 (또는 receive_bytes()로 이진 데이터)
            data = await websocket.receive_text()
            # 받은 메시지를 가공하여 다시 전송
            await websocket.send_text(f"Echo: {data}")
    except WebSocketDisconnect:
        # 연결 종료 시 처리할 로직
        print("클라이언트 연결 종료")

 

      2. app.add_websocket_route() 메소드 사용하기

         - 주요 특징

             - 프로그램적 등록: 데코레이터 대신 함수나 클래스를 사용해 WebSocket 라우트를 동적으로 등록할 수 있다.
             - 유연한 구성: 여러 라우트를 프로그램적으로 추가하거나, 라우트 구성이 동적으로 변경되어야 할 경우 유용하다.

 

         - 동작 과정

             - 핸들러 함수 정의:

                - 데코레이터를 사용하지 않고 별도의 함수(websocket_endpoint)를 정의한다.

         - 라우트 등록:

             - app.add_websocket_route("/ws", websocket_endpoint)를 호출하여 지정한 경로에 해당 핸들러를 등록한다.
         - 기능은 동일:

             - 등록된 핸들러는 데코레이터로 등록한 경우와 동일하게 클라이언트의 연결 수락, 메시지 처리, 예외 처리 등을 수행한다.


         - 기본 코드 예제

from fastapi import FastAPI, WebSocket
from starlette.websockets import WebSocketDisconnect

app = FastAPI()

async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Echo: {data}")
    except WebSocketDisconnect:
        print("클라이언트 연결 종료")

# '/ws' 경로에 대해 websocket_endpoint 함수를 등록
app.add_websocket_route("/ws", websocket_endpoint)

 

      3. 두 방법의 비교 및 선택 가이드

         - @app.websocket() 데코레이터

             - 장점: 코드가 간결하고 직관적이며, 정적 라우트 정의에 적합하다.

             - 사용 사례: 대부분의 경우 고정된 WebSocket 엔드포인트를 구현할 때 주로 사용한다.

 

         - app.add_websocket_route() 메소드

             - 장점: 라우트를 동적으로 추가하거나, 모듈화된 방식으로 관리할 때 유용하다.

             - 사용 사례: 라우트 구성을 프로그래밍적으로 제어해야 하거나, 조건에 따라 다수의 WebSocket 엔드포인트를 등록할 때 적합하다.

 

      4. 결론

         - FastAPI(또는 Starlette)에서는 WebSocket 연결을 지원하는 두 가지 방법, 데코레이터 방식과 메소드 방식을 제공하며, 두 방법 모두 동일한 기본 원리를 따른다.

             - @app.websocket() 데코레이터는 단순하고 직관적인 문법으로 고정된 엔드포인트를 정의할 때 유리하다.

             - app.add_websocket_route() 메소드는 보다 동적인 라우트 등록이 필요할 때 효과적이다.

 

         - 이 두 방법 중 프로젝트의 요구사항과 코드 구성 방식에 맞춰 적절한 방법을 선택하여 사용하면 됩니다.

 

3. 미들웨어 관련 메소드

   1) 일반적인 커스텀 미들웨어 추가

      - add_middleware의 첫번째 파라미터에 정의되는 메소드의 __init__ 메서드에서 정의된 매개변수이다.

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 미들웨어 함수 정의
async def custom_middleware(request: Request, call_next):
    # 요청 전처리 로직
    print("Custom middleware processing before request.")
    
    # 다음 미들웨어나 핸들러 호출
    response = await call_next(request)
    
    # 응답 후처리 로직
    print("Custom middleware processing after response.")
    
    return response

# 미들웨어를 FastAPI 앱에 추가
app.add_middleware(custom_middleware)

 

   2) CORS 미들웨어를 설정

# CORS 미들웨어 설정
origins = [
    "http://localhost",
    "http://localhost:8000",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"], # 허용할 오리진 목록
    allow_credentials=True, # 자격 증명 허용 여부
    allow_methods=["GET", "POST"], # 허용할 HTTP 메서드
    allow_headers=["Authorization", "Content-Type"], # 허용할 HTTP 헤더
)

 

4. 예외 처리 메소드

   1) 예외 핸들러 등록

      1. 커스텀 예외 클래스 정의

         - 먼저, 애플리케이션에서 발생할 수 있는 특정 상황을 처리하기 위해 사용자 정의 예외 클래스를 만든다.

         - CustomException 클래스는 예외 발생 시 이름을 전달받아 초기화 한다.

class CustomException(Exception):
    def __init__(self, name: str):
        self.name = name

 

      2. 예외 핸들러 함수 작성

         - 다음으로, 위에서 정의한 CustomException을 처리할 핸들러 함수를 작성한다.

         - 이 핸들러는 CustomException이 발생할 때 호출되며, JSON 형식의 응답을 반환한다.

from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse

async def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        status_code=418,  # I'm a teapot 상태 코드
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )

     

      3. 예외 핸들러 등록

         - FastAPI 애플리케이션 인스턴스에 예외 핸들러를 등록한다.

from fastapi import FastAPI

app = FastAPI()

app.add_exception_handler(CustomException, custom_exception_handler)

 

      4. 엔드포인트에서 예외 발생

         - 이제 엔드포인트에서 CustomException을 발생시켜 예외 핸들러가 작동하는지 확인한다.

@app.get("/items/{name}")
async def read_item(name: str):
    if name == "rainbow":
        raise CustomException(name=name)
    return {"name": name}

 

      5. 전체 코드

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, name: str):
        self.name = name

async def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )

app = FastAPI()

app.add_exception_handler(CustomException, custom_exception_handler)

@app.get("/items/{name}")
async def read_item(name: str):
    if name == "rainbow":
        raise CustomException(name=name)
    return {"name": name}

 

       6. add_exception_handler 없이 exception_handler를 이용해 간편하게 등록하는 방법

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, name: str):
        self.name = name

app = FastAPI()

@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        status_code=400,
        content={"message": f"An error occurred: {exc.name}"},
    )

@app.get("/items/{name}")
async def read_item(name: str):
    if name == "error":
        raise CustomException(name=name)
    return {"name": name}

 

5. 이벤트 핸들러 메소드

   1) @app.on_event 데코레이터를 사용한 이벤트 핸들러

      - 이전에는 @app.on_event 데코레이터를 사용하여 이벤트 핸들러를 정의했다.

      - 이 방법은 여전히 사용 가능하지만, FastAPI의 최신 버전에서는 lifespan 매개변수를 사용하는 것이 권장된다.

      - startup_event 함수는 애플리케이션이 시작될 때, shutdown_event 함수는 애플리케이션이 종료될 때 호출된다.

from fastapi import FastAPI

app = FastAPI()

@app.on_event("startup")
async def startup_event():
    # 애플리케이션 시작 시 실행할 코드
    print("애플리케이션이 시작되었습니다.")

@app.on_event("shutdown")
async def shutdown_event():
    # 애플리케이션 종료 시 실행할 코드
    print("애플리케이션이 종료되었습니다.")
from fastapi import FastAPI

# FastAPI 애플리케이션 인스턴스 생성
app = FastAPI()

# 데이터베이스 커넥션 예시 변수 (실제 코드에서는 데이터베이스 라이브러리 사용)
db_connection = None

# 애플리케이션 시작 시 실행될 이벤트 핸들러
@app.on_event("startup")
async def startup_event():
    global db_connection
    # 데이터베이스 연결 초기화 (예시 코드)
    db_connection = "DB 연결 생성"
    # 실제 코드에서는 await some_async_db_connect() 등 사용
    print("애플리케이션 시작: 데이터베이스 연결이 초기화되었습니다.")

# 애플리케이션 종료 시 실행될 이벤트 핸들러
@app.on_event("shutdown")
async def shutdown_event():
    global db_connection
    # 데이터베이스 연결 종료 (예시 코드)
    db_connection = None
    # 실제 코드에서는 await some_async_db_disconnect() 등 사용
    print("애플리케이션 종료: 데이터베이스 연결이 종료되었습니다.")

# 간단한 엔드포인트 예제
@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

 

   2) lifespan 매개변수를 사용한 이벤트 핸들러

      - FastAPI 0.65.0 버전부터는 lifespan 매개변수를 사용하는 것이 권장됩니다. 이를 통해 애플리케이션의 시작과 종료 시점에 실행할 코드를 더 명확하게 정의할 수 있다.

      - lifespan 함수는 @asynccontextmanager 데코레이터를 사용하여 정의되며, yield 이전의 코드는 애플리케이션 시작 시, yield 이후의 코드는 애플리케이션 종료 시 실행된다.

from contextlib import asynccontextmanager
from fastapi import FastAPI

@asynccontextmanager
async def lifespan(app: FastAPI):
    # 애플리케이션 시작 시 실행할 코드
    print("애플리케이션이 시작되었습니다.")
    yield
    # 애플리케이션 종료 시 실행할 코드
    print("애플리케이션이 종료되었습니다.")

app = FastAPI(lifespan=lifespan)
from fastapi import FastAPI
from contextlib import asynccontextmanager

# 예시: 리소스(예: 데이터베이스 커넥션)를 관리할 변수
db_connection = None

# lifespan 함수 정의 (애플리케이션의 시작과 종료 시점에 호출됨)
@asynccontextmanager
async def lifespan(app: FastAPI):
    global db_connection
    # 애플리케이션 시작 시 실행되는 코드
    db_connection = "DB 연결 생성 (lifespan)"
    # 실제 코드에서는 await some_async_db_connect() 사용
    print("Lifespan 시작: 데이터베이스 연결이 초기화되었습니다.")
    
    # yield 이전의 코드는 startup 시점에, yield 이후의 코드는 shutdown 시점에 실행됩니다.
    try:
        yield
    finally:
        # 애플리케이션 종료 시 실행되는 코드
        db_connection = None
        # 실제 코드에서는 await some_async_db_disconnect() 사용
        print("Lifespan 종료: 데이터베이스 연결이 종료되었습니다.")

# FastAPI 애플리케이션 인스턴스 생성 시 lifespan 함수를 등록
app = FastAPI(lifespan=lifespan)

# 간단한 엔드포인트 예제
@app.get("/")
async def read_root():
    return {"message": "Hello, World!"}

 

6. OpenAPI/Swagger 관련 메소드

   1) FastAPI 생성 시 기본 설정

      - FastAPI 애플리케이션 인스턴스를 생성할 때 여러 매개변수를 통해 OpenAPI 스키마와 문서화 엔드포인트를 제어할 수 있다.

 

      1. openapi_url

         - OpenAPI 스키마 JSON 파일의 URL을 지정한다.
         - 예) openapi_url="/openapi.json"
         - 값을 None으로 지정하면 OpenAPI 스키마 생성을 비활성화할 수 있다.

 

      2. docs_url

         - Swagger UI 문서 페이지의 URL을 지정한다.
         - 예) docs_url="/docs"
         - 값을 None으로 지정하면 Swagger UI를 비활성화할 수 있다.

 

      3. redoc_url

         - ReDoc 문서 페이지의 URL을 지정한다.
         - 예) redoc_url="/redoc"
         - 값을 None으로 지정하면 ReDoc을 비활성화할 수 있다.

 

      4. swagger_ui_parameters

         - Swagger UI의 동작 및 테마와 같은 추가 옵션을 설정할 수 있다.
         - 예) swagger_ui_parameters={"syntaxHighlight.theme": "monokai"}

from fastapi import FastAPI

app = FastAPI(
    title="My API",
    description="This is a sample API.",
    version="1.0.0",
    openapi_url="/openapi.json",
    docs_url="/docs",
    redoc_url="/redoc",
    swagger_ui_parameters={"syntaxHighlight.theme": "monokai"},
)

 

2. OpenAPI 스키마 생성 및 커스터마이징

   1) 기본 OpenAPI 스키마 자동 생성

      - FastAPI는 애플리케이션의 모든 경로와 모델(Pydantic)을 분석하여 OpenAPI 스키마를 자동 생성한다. 이 스키마는 /openapi.json 엔드포인트에서 확인할 수 있다.

 

   2) get_openapi() 함수

      - fastapi.openapi.utils.get_openapi 함수를 사용하면 현재 앱의 속성(예: title, version, description, routes)을 바탕으로 OpenAPI 스키마를 생성할 수 있다. 이 함수를 오버라이드하여 사용자 정의 스키마를 만들 수 있다.

      - 이렇게 재정의하면, /openapi.json에 반영된 스키마에 사용자 정의 필드나 변경 사항을 추가할 수 있다.

from fastapi.openapi.utils import get_openapi

def custom_openapi():
    if app.openapi_schema:  # 이미 생성된 경우 캐시된 스키마 반환
        return app.openapi_schema
    openapi_schema = get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        routes=app.routes,
    )
    # 필요한 커스터마이징을 추가할 수 있음
    openapi_schema["info"]["x-custom"] = "Custom value"
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

 

3. 추가 커스터마이징 옵션

   1) openapi_tags

      - 라우터 데코레이터의 tags 인자를 통해 엔드포인트를 그룹화하면, 자동 생성된 문서에서 태그별 섹션으로 정리되어 표시된다.

@app.get("/items/", tags=["items"])
async def read_items():
    return [{"item_id": "Foo"}]

 

   2) 요약 및 설명

      - 각 엔드포인트에 summary와 description 매개변수를 지정하면, 문서에 해당 설명이 반영되어 사용자가 엔드포인트의 역할을 쉽게 이해할 수 있다.

@app.post("/items/", summary="아이템 생성", description="새로운 아이템을 생성합니다.")
async def create_item(item: Item):
    return item

 

7. CORS 설정 메소드

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:8080", "https://example.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["*"],
    max_age=3600
)

 

   - 매개변수:

      - allow_origins: 허용할 출처 목록
      - allow_credentials: 인증 정보 허용 여부
      - allow_methods: 허용할 HTTP 메소드 목록
      - allow_headers: 허용할 HTTP 헤더 목록
      - max_age: 프리플라이트 요청 캐시 시간(초)

 

8. 서브 애플리케이션 및 정적 파일 마운트

   1) mount() 메소드

      - mount()를 사용하면 별도의 ASGI 애플리케이션(예: Starlette의 StaticFiles)을 특정 경로에 "마운트"할 수 있다.

 

      - 예시 (정적 파일 제공):

from starlette.staticfiles import StaticFiles

app.mount("/static", StaticFiles(directory="static"), name="static")

 

9. 백그라운드 태스크 실행

   - FastAPI는 Starlette의 BackgroundTasks 클래스를 활용하여 백그라운드 태스크를 지원한다. 사용 방법은 다음과 같다.

 

   1) 백그라운드 태스크 인스턴스 주입:

      - 경로 함수의 매개변수로 BackgroundTasks 타입을 선언하면 FastAPI가 자동으로 인스턴스를 생성하여 주입한다.

 

   2) 태스크 등록:

      - background_tasks.add_task() 메서드를 사용하여 실행하고자 하는 함수를 등록한다. 이때 인자나 키워드 인자도 함께 전달할 수 있다.

 

   3) 즉시 응답 반환:

      - 태스크가 등록되면 함수는 바로 응답을 반환한다. 등록된 태스크는 응답이 전송된 후에 순차적으로 실행된다.

 

   4) 실행 시점:

      - FastAPI는 HTTP 응답이 성공적으로 클라이언트에 전송된 후에, 등록된 모든 백그라운드 태스크를 실행한다.
      - 만약 경로 함수 내에서 예외가 발생하여 응답을 반환하지 못하면, 등록된 백그라운드 태스크는 실행되지 않는다.

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

# 동기 함수 예시 (def로 정의)
def write_log(message: str):
    with open("log.txt", "a") as file:
        file.write(message + "\n")

@app.get("/")
async def read_root(background_tasks: BackgroundTasks):
    # 백그라운드 태스크 등록
    background_tasks.add_task(write_log, "로그 메시지")
    return {"message": "작업이 백그라운드에서 실행됩니다."}

 

10. dependency_overrides를 이용한 의존성 주입

   - FastAPI의 의존성 주입 시스템은 테스트나 특정 환경에서 실제 의존성 대신 다른 동작을 주입할 수 있도록   dependency_overrides  기능을 제공한다.

   - 이를 통해 실제 리소스(예: 데이터베이스 연결, 외부 API 호출 등)를 사용하지 않고도, 모의 객체(mock)나 간소화된 로직을 사용하여 테스트를 진행하거나 환경에 맞게 동작을 변경할 수 있다.

 

   1) 사용법

      1. 오버라이딩 함수 정의:

         - 원래 의존성이 제공하는 값을 대체할 함수를 작성한다.

 

      2. 오버라이딩 등록:

         - 앱 객체의 dependency_overrides에 원래 함수와 대체 함수를 등록한다.

app.dependency_overrides[원래_의존성함수] = 오버라이딩_함수

 

      3. 테스트 또는 실행 시 활용:

         - 이후 해당 의존성이 필요한 경로 함수는 오버라이딩된 함수의 결과를 사용한다.

 

from fastapi import FastAPI, Depends
from fastapi.testclient import TestClient

app = FastAPI()

# 실제 DB 연결을 위한 의존성 함수
def get_db():
    return "Real DB Connection"

@app.get("/items/")
def read_items(db=Depends(get_db)):
    return {"db": db}

# 테스트를 위해 DB 연결 대신 사용할 오버라이딩 함수
def override_get_db():
    return "Fake DB Connection"

# dependency_overrides에 오버라이딩 함수 등록
app.dependency_overrides[get_db] = override_get_db

# TestClient를 사용하여 테스트 실행
client = TestClient(app)

def test_read_items():
    response = client.get("/items/")
    assert response.json() == {"db": "Fake DB Connection"}

# 테스트 실행 시, read_items 엔드포인트는 get_db 대신 override_get_db의 결과를 사용하게 됩니다.

 

   2) 주요 포인트

      1. 테스트 용이성:

         - 실제 데이터베이스나 외부 서비스에 의존하지 않고 테스트 할 수 있으므로, 테스트 속도와 안정성이 향상된다.

 

      2. 유연성:

         - 특정 환경(예: 개발, 프로덕션, 테스트)에 따라 동일한 경로 함수라도 다른 동작을 하도록 설정할 수 있다.

 

      3. 전역 적용:

         - app.dependency_overrides에 등록된 오버라이딩은 전역적으로 적용되므로, 모든 요청에서 해당 의존성이 오버라이딩된 함수로 대체된다.

 

 

 

- reference : 

https://fastapi.tiangolo.com/ko/advanced/middlewares/

 

고급 미들웨어 - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

https://limsw.tistory.com/142

 

[FastAPI] Lifespan을 이용한 생명주기 관리 (Event Handler)

서론 이번 글에서는 FastAPI의 Lifespan을 이용하여 이벤트를 관리하는 방법을 알아보고자 한다. 이 글에서 말하는 이벤트 핸들링은 FastAPI 서비스가 시작 또는 종료될 때 특정 함수를 호출하는 등의

limsw.tistory.com

https://fastapi.tiangolo.com/ko/advanced/events/

 

이벤트: startup과 shutdown - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

https://fastapi.tiangolo.com/advanced/events/

 

Lifespan Events - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

https://mopil.tistory.com/entry/FastAPI-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-w-fastapi-events

 

[FastAPI] 이벤트 기반 아키텍처 구축하기 (w. fastapi-events)

FastAPI 프레임워크로 이벤트 기반 아키텍처를 구축하는 방법에 대해 공유한다. # 이벤트 기반 아키텍처란? 새로운 댓글 작성 시, 게시물 작성자에게 알림을 보내야 하는 기능을 구현해야 한다고

mopil.tistory.com

 

댓글