Reputation: 8208
I'm using Python 3.6 and the aiohttp library to make an API Post request to a server. If I use the wrong username when making the request, I get an HTTP 403 error as I expect. When I make this request in Postman, the body of the response shows:
{"error_message": "No entitlements for User123"}
When I make the request using aiohttp however, I don't see this response body anywhere. The message just says "Forbidden". How can I get the error message above in my Python code?
Edit: Here's my aiohttp code, although it's pretty straightforward:
try:
async with self.client_session.post(url, json=my_data, headers=my_headers) as response:
return await response.json()
except ClientResponseError as e:
print(e.message) # I want to access the response body here
raise e
Edit 2: I found a workaround. When I'm creating the client_session
, I set the raise_for_status value to False. Then when I get a response from the API call, I check if the status is >= 400. If so, I handle the error myself, which includes the body of the response.
Edit 3: Here's the code for my workaround:
self.client_session = ClientSession(loop=asyncio.get_event_loop(), raise_for_status=False)
####################### turn off the default exception handling ---^
try:
async with self.client_session.post(url, json=my_data, headers=my_headers) as response:
body = await response.text()
# handle the error myself so that I have access to the response text
if response.status >= 400:
print('Error is %s' % body)
self.handle_error(response)
Upvotes: 5
Views: 5989
Reputation: 9879
Yes, it may be indeed confusing if you are coming from requests
package that has its exception objects having .request.response
(or the other way around) attribute.
You've already figured that out obviously, but here is a proper answer for the older versions of aiohttp.
async with session.post(...) as response:
try:
response.raise_for_status()
except ClientResponseError as err:
logger.error("Error: %s, Error body: %s", err, (await response.text()))
return await response.json()
The newer versions unfortunately recycle the connection once raise_for_status()
is called hence you can't fetch the error body later. Here is what work for me nowadays (from http-noah package):
logger = structlog.get_logger(__name__)
async with session.post(url, **req_kwargs) as res:
# Fetching text as error just in case - raise_for_status() will
# release the connection so the error body will be lost already.
# The text will be cached in the response internally for the use later on
# so no waste here.
err_body = await res.text()
try:
res.raise_for_status()
except aiohttp.ClientResponseError as err:
logger.error("Request failed", err=err, err_body=err_body)
raise
Upvotes: 4