Search code examples
pythonrestpython-asyncioaiohttp

Python - aiohttp API response content is "StreamReader" type instead of JSON


I'm learning the aiohttp library with Python 3.10 for making HTTP GET requests, and am practising it with the GitHub v3 REST API. Here's my code for a basic request:

# Python Standard Library imports
import asyncio
import sys

# External library imports
import aiohttp

# GitHub API v3 REST endpoint for licenses
GITHUB_URL: str = "https://api.github.com/licenses"
# GitHub query headers
GITHUB_HEADERS: dict = {
    "Accept": "application/vnd.github.v3+json"
}

async def main():

    async with aiohttp.ClientSession() as session:
        async with session.get(GITHUB_URL, headers = GITHUB_HEADERS) as GitHub_response:

            print(GitHub_response.content)

if __name__ == "__main__": 

    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

    sys.exit(0)

The code runs without errors, but the critical print(GitHub_response.content line gives me:

<StreamReader 2037 bytes eof>

Which is not what I expected. And what is a StreamReader object anyway???

What I expected was the JSON output which the curl command curl -H "Accept: application/vnd.github.v3+json" "https://api.github.com/licenses would give me, which looks like:

[
  {
    "key": "agpl-3.0",
    "name": "GNU Affero General Public License v3.0",
    "spdx_id": "AGPL-3.0",
    "url": "https://api.github.com/licenses/agpl-3.0",
    "node_id": "MDc6TGljZW5zZTE="
  },
  {
    "key": "bsd-2-clause",
    "name": "BSD 2-Clause \"Simplified\" License",
    "spdx_id": "BSD-2-Clause",
    "url": "https://api.github.com/licenses/bsd-2-clause",
    "node_id": "MDc6TGljZW5zZTQ="
  },
.....

I tried replacing my print() line with print(GitHub_response.json()), but that gave me:

<coroutine object ClientResponse.json at 0x7f7e452b5e00>

So it is still not the JSON I was expecting.

What did I do wrong? And how do I fix my Python code so that I get the actual JSON response with aiohttp?

P.S. I tried doing the above with the Python requests library. The content of the response in this case is a bytes object which I had to decode("utf8") first before using json.dumps() from the json library to turn it into actual JSON. Not sure if this information is helpful for figuring out what I messed up when using aiohttp.


Solution

  • "content" is an instance of StreamReader. This provides a coroutine "read" that reads returns the content as string. Insert the following example into your code and you should get the expected result.

     x = await GitHub_response.content.read()
     print(x.decode("utf8"))