포스트

[FastAPI] <3 : 의존성 주입>

공식 문서

1. 의존성 주입이 필요한 이유

공통된 로직(반복된 코드)가 필요한 경우

보안, 인증 등 요구사항을 강제해야 하는 경우(이 부분은 Security로 가능하다.)

db 연결을 하는 경우(api_key?)

등등의 예에서 코드 반복을 줄여준다.

2. Depends 사용예

해당 작업들을 FastAPI에선 Depends를 불러와 해결한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()

async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
	return {"q": q, "skip": skip, "limit": limit}
	
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
	return commons

@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
	return commons

특정 엔드포인트(/items/, /users/)에 진입하게 된다면 Query로 commons 값을 읽어오게 된다. 이때 commons 값은 반드시 Depends에서 매개변수로 입력한 함수를 통과해야 하는데 이 것을 의존성 주입이라고 한다. 이때 commom_parameters를 직접 호출하지 않는 모습을 보여준다.

이때 common_parameters는 기본값이 None인 str q, 기본값이 0인 int skip, 기본값이 100인 int limit를 key로 가진 dict을 리턴한다.

/items/ 로 접근한다면 다음을 리턴한다.

1
2
3
4
5
{
    "q": null,
    "skip": 0,
    "limit": 100
}

기본값 대신 쿼리로 값을 지정한다고 해보자.

/items/?q=hi&skip=10&limit=50 으로 접근한다면 다음의 값을 리턴한다.

1
2
3
4
5
{
    "q": "hi",
    "skip": 10,
    "limit": 50
}

이 것을 /users/ 에도 똑같이 적용 가능하다.

우리는 Depends를 통해 코드의 반복 사용을 줄일 수 있다.

3. 전역 의존성

어떤 경우에는 전체 앱의 실행 과정에서 특정 함수가 사용되야할 경우도 있을 것이다.

이 때는 FastAPI 인스턴스 생성시에 Depends를 달아주면 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
from fastapi import Depends, FastAPI, Header, HTTPException
from typing_extentions import Annotated

async def verify_token(x_token: Annotated[str, Header()]):
		if x_token != "fake-super-token"
				raise HTTPException(status_code=400, detail="X-Token header invalid")

async def verify_key(x_key: Annotated[str, Header()]):
    if x_key != "fake-super-secret-key":
        raise HTTPException(status_code=400, detail="X-Key header invalid")
    return x_key

app = FastAPI(dependencies = [Depends(verify_token), Depends(verify_key)])

이렇게 인스턴스 생성 시에 의존성을 달아준다면, 모든 경로의 Header에서 읽어온 token과 key로 verify_token과 verify_key를 실행한다.

물론, 이것과 같은 과정으로 특정 prefix에서만의 의존성도 주입 가능하다.

1
specific_router = APIRouter(prefix="/users", tags=["users"], dependencies = [Depends(some_func1), Depends(some_func2)])


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.