Api Requests With Python

Author: Joe Hutcheson

Regardless of the programming language, creating API requests are an essential part of a developers work. For new developers or experienced developers new to a particular langauge, getting out of your own machine and into the good old world wide web can be empowering. To accommodate this, Python provides the urllib package in the standard library, which does the trick in conjunction with the json module. Given the option, developers may instead choose to install and import the requests third-party library for cleaner code and a more direct approach.

For the following examples, we will access the Open Notify API Server which holds the names of all astronauts currently in space. With the help of the standard library’s pretty print module, we could achieve something like this:

{'message': 'success',
 'number': 10,
 'people': [{'craft': 'ISS', 'name': 'Sergey Prokopyev'},
            {'craft': 'ISS', 'name': 'Dmitry Petelin'},
            {'craft': 'ISS', 'name': 'Frank Rubio'},
            {'craft': 'Shenzhou 15', 'name': 'Fei Junlong'},
            {'craft': 'Shenzhou 15', 'name': 'Deng Qingming'},
            {'craft': 'Shenzhou 15', 'name': 'Zhang Lu'},
            {'craft': 'ISS', 'name': 'Stephen Bowen'},
            {'craft': 'ISS', 'name': 'Warren Hoburg'},
            {'craft': 'ISS', 'name': 'Sultan Alneyadi'},
            {'craft': 'ISS', 'name': 'Andrey Fedyaev'}]}

The urllib package contains a handful of useful modules. To retrieve the information above, we would use urllib.request. The built-in json module allows us to work with the returned json data.

#!/usr/bin/python3
"""Alta3 Research
Using the urllib library"""

import urllib.request
import json

The call to our API will look like the following:

open_notify_API = "http://api.open-notify.org/astros.json"
astronauts_in_space = urllib.request.urlopen(open_notify_API)

This returns a response object:

<http.client.HTTPResponse object at 0x7fd332b200d0>

…on which we can call a .read() function.

astronauts_in_space = astronauts_in_space.read()

The data held in this variable needs to be decoded to utf-8:

astronauts_in_space = astronauts_in_space.decode("utf-8")

But why use three lines of code when we can use just one? Let’s tidy things up by chaining our methods:

astronauts_in_space = urllib.request.urlopen(open_notify_API).read().decode("utf-8")

If printed to the console, this might look like a dictionary, but not so fast. Python will take issue with this data if you try to treat it like one. The following code will render an error:

print(astronauts_in_space["people"]

TypeError: string indices must be integers

Our variable above actually represents a string that happens to look like a dictionary. The .loads() method from the JSON module will convert the data to a Pythonic dictionary:

astronauts_in_space = json.loads(astronauts_in_space)

A full script rendering this data to our console would look like this:

#!/usr/bin/python3
"""Alta3 Research
Using the urllib library"""

from pprint import pprint # to "pretty print" out our response data
import urllib.request
import json

def main():
    open_notify_API = "http://api.open-notify.org/astros.json"
    astronauts_in_space = urllib.request.urlopen(open_notify_API).read().decode("utf-8")
    astronauts_in_space = json.loads(astronauts_in_space)
    pprint(astronauts_in_space)

if __name__ == "__main__":
    main()

The same thing can be accomplished in a slightly tidier manner using the 3rd party requests library, which will need to be installed:

python -m pip install requests

Only one import is required using this library:

#!/usr/bin/python3
"""Alta3 Research
Using the requests library"""

import requests

The .get() method is called from the requests library on our URL:

open_notify_API = "http://api.open-notify.org/astros.json"
astronauts_in_space = requests.get(open_notify_API)

The response object looks a bit different here: <Response [200]>. The JSON can be stripped off easily:

astronauts_in_space = astronauts_in_space.json()

We can simplify things by chaining here as well:

astronauts_in_space = requests.get(open_notify_API).json()

Using the requests library, the script returning our Pythonic dictionary version of the JSON data would look like this:

#!/usr/bin/python3
"""Alta3 Research
Using the requests library"""

from pprint import pprint

import requests

def main():
    open_notify_API = "http://api.open-notify.org/astros.json"
    astronauts_in_space = requests.get(open_notify_API).json()
    pprint(astronauts_in_space)
    
if __name__ == "__main__":
    main()

Both methods work. If you’re in an environment where you have limited reach into 3rd party libraries, then urllib is your best choice. However, if using 3rd party libraries isn’t a concern, than reach for the requests library, which provides more abstraction and, therefore, better overall readiblity of your Python code.