Hooking 기능¶
ahttp_client 패키지에서 후킹이란 HTTP 요청이 있기 전과 후에 데이터를 처리하는 기능을 의미합니다. 세션 단위 후킹과 요청 단위 후킹으로 나누어집니다.
후킹 기능은 보통 아래와 같이 이용됩니다.
- Before Hook (HTTP 요청 이전):
인증과 같이 필요한 HTTP 구성요소를 설정합니다.
인수가 올바르게 입력되었는지 검증합니다.
- After Hook (HTTP 요청 이후):
원본 데이터를 데이터클래스에 파싱합니다.
HTTP 상태 코드에 따라 적절한 조치합니다.
참고
여기서는 세션 단위의 before_request/after_request 후킹과 요청 단위의 before_hook/after_hook 데코레이터만 다룹니다. 재시도가 after_request 와 어떻게 맞물리는지는 재시도 (Retry) 문서를 참고하시고, 후킹에서 발생시키는 HTTPException 계층 구조가 궁금하다면 예외 (Exception) 을 보시면 됩니다.
세션 후킹(Session Hooking)¶
세션 단위의 후킹은 메소드를 오버라이딩하는 방식으로 만듭니다.
1class GithubService(AsyncSession):
2 def __init__(self, token: str):
3 self._token = token # Private Attribute
4 super().__init__("https://api.github.com", aiohttp.ClientSession)
5
6 # overriding before_request method
7 async def before_request(self, req_obj: RequestCore, path: str):
8 req_obj.headers["Authorization"] = self._token
9 req_obj.headers["Accepts"] = "application/vnd.github+json;"
10 return req_obj, path
11
12 # overriding after_request method
13 async def after_request(self, response: Response):
14 if response.status != 200:
15 raise HTTPException()
16 return response
17
18 @request("GET", "/users/{user}/repos")
19 async def list_repositories(
20 self, response: Response, user: Annotated[str, Path]
21 ) -> list[dict[str, Any]]:
22 return response.json()
GithubService 객체는 before_request 와 after_request 를 오버라이딩하여 정의합니다.
인증에 필요한 토큰을 비공개 속성 값으로 저장해두고, before_request 메소드에서 header에 그 값을 삽입합니다. list_repositories 메소드와 같이 GithubService 객체에 소속된 메소드가 호출되면, 필요한 HTTP 구성요소를 삽입하기 위해 before_request 메소드가 먼저 호출됩니다.
HTTP 요청이 끝나면, after_request 메소드가 호출되어 HTTP 상태 코드를 확인합니다. 상태 코드가 200 (OK)이 아니라면, 사전에 정의된 예외인 HTTPException 이 발생합니다 (예외 (Exception) 참고).
요청 후킹(Request Hooking)¶
요청 단위의 후킹은 데코레이터 메소드를 이용하여 생성하게 됩니다.
1token = "GITHUB TOKEN"
2
3@AsyncSession.single_session("https://api.github.com", aiohttp.ClientSession)
4@request("GET", "/repos/{user}/{repo}/topics")
5async def repository_topic(
6 session: AsyncSession,
7 response: Response,
8 user: Annotated[str, Path],
9 repo: Annotated[str, Path]
10) -> list[str]:
11 return response.json()["names"]
12
13# before_hook method
14@repository_topic.before_hook
15async def before_hook(session: AsyncSession, req_obj: RequestCore, path: str):
16 req_obj.headers["Authorization"] = token
17 req_obj.headers["Accepts"] = "application/vnd.github+json;"
18 return req_obj, path
19
20# after_hook method
21@repository_topic.after_hook
22async def after_hook(session: AsyncSession, response: Response):
23 if response.status != 200:
24 raise HTTPException()
25 return response
깃허브 레포지토리의 주제를 가져오기 위해 repository_topic 메소드를 정의하였습니다. 그리고 같은 메소드의 before_hook 과 after_hook 데코레이터 메소드를 이용하여 후킹을 정의하였습니다.
before_hook 메소드에서는 필요한 구성 요소(인증키 등)를 HTTP 요청이 있기 전에 삽입하는 역할을 합니다.
after_hook 메소드는 요청 함수가 JSON 데이터를 파싱하기 전에 응답을 검증합니다.
경고
요청 단위의 after_hook 은 재시도 (Retry) 시도가 다 끝난 뒤에 실행됩니다. 그래서 retry_on 에 적힌 예외를 여기서 발생시켜도 재시도 대상이 되지는 않습니다.