Search code examples
pythonaiohttpfastapi

AIOHTTP having request body/content/text when calling raise_for_status


I'm using FastAPI with aiohttp, I built a singleton for a persistent session and I'm using it for opening the session at startup and closing it at shutdown.

Demand: The response body is precious in case of a failure I must log it with the other details.

Because how raise_for_status behave I had to write those ugly functions which handle each HTTP method, this is one of them:

async def post(self, url: str, json: dict, headers: dict) -> ClientResponse:
    response = await self.session.post(url=url, json=json, headers=headers)
    response_body = await response.text()

    try:
        response.raise_for_status()
    except Exception:
        logger.exception('Request failed',
                         extra={'url': url, 'json': json, 'headers': headers, 'body': response_body})
        raise

    return response

If I could count on raise_for_status to return also the body (response.text()), I just could initiate the session ClientSession(raise_for_status=True) and write a clean code:

response = await self.session.post(url=url, json=json, headers=headers)

Is there a way to force somehow raise_for_status to return also the payload/body, maybe in the initialization of the ClientSession?

Thanks for the help.


Solution

  • It is not possible for aiohttp and raise_for_status. As @Andrew Svetlov answered here:

    Consider response as closed after raising an exception. Technically it can contain a partial body but there is no any guarantee. There is no reason to read it, the body could be very huge, 1GiB is not a limit. If you need a response content for non-200 -- read it explicitly.

    Alternatively, consider using the httpx library in this way. (It is widely used in conjunction with FastAPI):

    def raise_on_4xx_5xx(response):
        response.raise_for_status()
    
    async with httpx.AsyncClient(event_hooks={'response': [raise_on_4xx_5xx]}) as client:
        try:
            r = await client.get('http://httpbin.org/status/418')
        except httpx.HTTPStatusError as e:
            print(e.response.text)