TL;DR

  • Header는 http request body가 아니라 header에서 받고 싶은 필드가 있을 때 사용한다.
  • Depends는 함수에 대한 wrapper로 입력으로 들어온 필드에 대해서 감싸고 있는 함수에 인자로 넣어 반환된 값을 사용하고 싶을 때 사용한다.
    • API를 사용할 때마다 Authorization 필드에 대해서 인증을 해야되는데, 이런 재사용성이 높은 함수를 위해 Depends를 사용한다.
    • 이런 걸 Dependency Injection이라고 하는 것 같다?

Header

  • 예를 들어, 헤더의 Authorization 필드를 따로 받아 처리하고 싶다면 다음과 같이 쓰면 된다.
from fastapi import APIRouter, Header, HTTPException, status  
  
router = APIRouter()  
  
@router.get('/')  
async def simple_verify(authorization: str = Header(None)):  
	if authorization is not None:  
		return authorization  
	raise HTTPException(  
		status_code = status.HTTP_401_UNAUTHORIZED,  
		detail = "Invalid authentication token"  
	)  
  • 근데 이렇게 하면 /docs에서 Swagger가 자동으로 만들어 준 API 테스트 기능을 사용하지 못하는 것 같다.
  • 개인적으로는 Authorization 필드가 중요한 필드라서 임의로 이렇게 처리하는 걸 막는 것 같은 느낌이다.

Depends

  • 이미 잘 만들어진 인증을 위한 함수를 받아와서 사용하니 이런 이슈가 해결되었다.
from fastapi import APIRouter, Depends, HTTPException, status  
from fastapi.security import HTTPBearer  
from jose import jwt  
  
router = APIRouter()  
  
SECRET = "your-secret-here"  
ALGORITHM = "HS256"  
  
security = HTTPBearer()  
async def verify_token(credentials = Depends(security)) -> str:  
    try:  
        payload = jwt.decode(credentials.credentials,   
					         SECRET,   
					         algorithms=[ALGORITHM])           
        username: str = payload.get("sub")  
        if username is None:  
            raise HTTPException(  
                status_code=status.HTTP_401_UNAUTHORIZED,  
                detail="Invalid authentication token"  
            )  
        return username  
    except JWTError:  
        raise HTTPException(  
            status_code=status.HTTP_401_UNAUTHORIZED,  
            detail="Invalid authentication token"  
        )  
  • HTTPBearer는 정확히는 모르겠지만, 아마 헤더에서 Authorization 필드를 긁어와서 그걸 객체로 만들어서 쓰기 좋게 반환해주는 것 같다.
    • 위 코드에선 credentials.credentials에는 JWT 토큰이 들어오기를 기대하고 있다.
    • 참고로 credentials.scheme에는 Bearer라고 값이 들어있다.
  • 자세히 보면 이 함수에는 @router와 같은 데코레이터가 없는데, 이 또한 Depends로 넘겨주기 위한 함수이기 때문이다.
@router.get("/")  
async def root(user_name: str = Depends(verify_token)):  
	return user_name  
  • 함수의 인자 user_name을 query string으로 넘겨주지 않아도 동작하는 걸 보면, Depends를 타고 타고 올라가면서 가장 처음에 실행되는 함수에 대한 인자를 더 중요시 여기는 것 같다.