Pre Hooking / Post Hooking

In ahttp_client, hooking means refining data before and after an HTTP request is received. A hooking supports session unit hooking and request unit hooking.

A hooking is used as follows.

  • Before Hook (Pre-request):
    • Set up the required HTTP component (e.g. authorization).

    • Validate that the correct arguments are given.

  • After Hook (Post-request)
    • Parse the raw response data into a data class.

    • Act based on the HTTP status code.

Note

This page only covers the session-level before_request/after_request hooks and the request-level before_hook/after_hook decorators. For how retries interact with after_request, see Retry. For the HTTPException hierarchy a hook can raise, see Exception.

Session Hooking

A Session unit hooking is created by overridding a method.

Hooking of Session Unit Example
 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 overrides before_request and after_request directly.

The token is stored as a private attribute, and before_request inserts it into the header. Whenever a method on the object is called, such as list_repositories, before_request runs first and adds the HTTP components a request needs.

after_request runs once the HTTP request finishes and checks the status code. A status other than 200 (OK) raises HTTPException, a predefined exception (see Exception).

Request Hooking

A request unit hooking is created using the decorating method.

Hooking of Request Unit Example
 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 fetches the topics of a repository, and its before_hook/after_hook decorators define the hooking right on that same method.

before_hook inserts what the request needs (an authorization key, for example) before repository_topic makes the HTTP call.

after_hook validates the response before the request function parses the JSON.

Warning

A request-level after_hook always runs after any Retry attempts have finished. It is not retried itself, even if it raises an exception listed in retry_on.