[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)])