Python & APIs: A Winning Combo for Reading Public Data

Python & APIs: A Winning Combo for Reading Public Data

by Pedro Pregueiro Jul 24, 2023 api intermediate

Knowing how to consume an API is one of those magical skills that, once mastered, will crack open a whole new world of possibilities, and consuming APIs using Python is a great way to learn such a skill.

A lot of apps and systems that you use on a daily basis are connected to an API. From very simple and mundane tasks, like checking the weather in the morning, to more addictive and time-consuming actions, such as scrolling through your Instagram, TikTok, or Twitter feed, APIs play a central role.

In this tutorial, you’ll learn:

  • What an API is
  • How you can consume APIs with your Python code
  • What the most important API-related concepts are
  • How Python can help you read data that’s available through public APIs

By the end of this tutorial, you’ll be able to use Python to consume most of the APIs that you come across. If you’re a developer, then knowing how to consume APIs with Python will make you much more proficient, especially when it comes to integrating your work with third-party applications.

You can download the source code for the examples that you’ll see in this tutorial by clicking the link below:

Getting to Know APIs

API stands for application programming interface. In essence, an API acts as a communication layer, or interface, that allows different systems to talk to each other without having to understand exactly what the others do.

APIs can come in many forms or shapes. They can be operating system APIs, used for actions like turning on your camera and audio when joining a Zoom call. Or they can be web APIs, used for web-focused actions, such as liking images on your Instagram or fetching the latest tweets.

No matter the type, all APIs function mostly the same way. You usually make a request for information or data, and the API returns a response with what you requested. For example, every time you open Twitter or scroll down your Instagram feed, you’re basically making a request to the API behind that app and getting a response in return. This is also known as calling an API.

In this tutorial, you’ll focus more on the high-level APIs that communicate across networks, also called web APIs.

SOAP vs REST vs GraphQL

Even though some of the examples above are geared toward newer platforms or apps, web APIs have been around for quite a long time. In the late 1990s and early 2000s, two different design models became the norm in exposing data publicly:

  1. SOAP (Simple Object Access Protocol) is typically associated with the enterprise world, has a stricter contract-based usage, and is mostly designed around actions.
  2. REST (Representational State Transfer) is typically used for public APIs and is ideal for fetching data from the Web. It’s much lighter and closer to the HTTP specification than SOAP.

Nowadays, there’s a new kid in town: GraphQL. Created by Facebook, GraphQL is a very flexible query language for APIs, where the clients decide exactly what they want to fetch from the server instead of letting the server decide what to send.

If you want to learn more about the differences between these three design models, then here are a few good resources:

Even though GraphQL is on the rise and is being adopted by bigger and bigger companies, including GitHub and Shopify, the truth is that the majority of public APIs are still REST APIs. Therefore, for the purpose of this tutorial, you’ll learn only about REST APIs and how to consume them using Python.

APIs and requests: A Match Made in Heaven

When consuming APIs with Python, there’s only one library you need: requests. With it, you should be able to do most, if not all, of the actions required to consume any public API.

You can install requests by running the following command in your console:

$ python -m pip install requests

The examples in this tutorial have been tested with Python 3.11.2 and requests 2.31.0. However, any supported version of Python and requests should yield similar results.

Calling Your First API Using Python

Enough talking—it’s time to make your first API call! For the first example, you’ll be calling a popular API for generating random user data.

Throughout the tutorial, you’ll see new APIs introduced in alert blocks like the one below. It’s a convenient way for you to scroll through afterward and quickly spot all the new APIs that you learned about.

All you need to start with the Random User Generator API is to know which URL to call it with. For this example, the URL to use is https://randomuser.me/api/, and this is the tiniest API call that you can make:

>>>
>>> import requests
>>> requests.get("https://randomuser.me/api/")
<Response [200]>

In this small example, you import the requests library and then fetch, or get, data from the URL for the Random User Generator API. But you don’t actually see any of the data returned. What you get instead is a Response [200], which in API terms means everything went okay.

If you want to see the actual data, then you can use .text from the returned Response object:

>>>
>>> import requests
>>> response = requests.get("https://randomuser.me/api/")
>>> response.text
'{"results":[{"gender":"female",
"name":{"title":"Ms","first":"Isobel","last":"Wang"}...'

That’s it! Now you know the absolute basics of API consumption. You managed to fetch your first random user from the Random User Generator API using Python and the requests library.

Endpoints and Resources

As you saw above, the first piece of information necessary for consuming an API is the API URL, typically called the base URL. The base URL structure is no different from the URLs that you use for browsing Google, YouTube, or Facebook, though it usually contains the word api. This isn’t mandatory, just more of a rule of thumb.

For example, here are the base URLs for a few well-known API players:

  • https://api.twitter.com
  • https://api.github.com
  • https://api.stripe.com

As you can see, all of the above start with https://api and include the remaining official domain, such as .twitter.com or .github.com. There’s no specific standard for how the API base URL should look, but it’s quite common for it to mimic this structure.

If you try opening any of the above links, then you’ll notice that most of them will return an error or ask for credentials. That’s because APIs sometimes require authentication steps before you can use them. You’ll learn more about this a bit later in the tutorial.

Next, using the Cat API, you’ll try to make a basic request to see how it may differ from the Random User Generator API that you tried above:

>>>
>>> import requests
>>> response = requests.get("https://api.thecatapi.com/")
>>> response.text
'{"message":"The Cat API","version":"1.2.5"}'

In this case, when calling the base URL, you get this generic message saying "The Cat API". This is because you’re calling the base URL, which is typically used for very basic information about an API, not the real data.

Calling the base URL alone isn’t a lot of fun, but that’s where endpoints come in handy. An endpoint is a part of the URL that specifies what resource you want to fetch. Well-documented APIs usually contain an API reference, which is extremely useful for knowing exactly which endpoints and resources an API has and how to use them.

You can check the official documentation to learn more about how to use the Cat API and what endpoints are available. In there, you’ll find a /breeds endpoint that you can use to fetch all the available breed resources or objects.

Now, give it a try in code locally using the breeds endpoint and some of the API knowledge that you already have:

>>>
>>> response = requests.get("https://api.thecatapi.com/v1/breeds")
>>> response.text
'[{"weight":{"imperial":"7  -  10","metric":"3 - 5"},"id":"abys",...}]'

There you go, your first breed listing using the Cat API!

If you’re a dog person, don’t fret. There’s an API for you, too, with the same endpoint but a different base URL:

>>>
>>> response = requests.get("https://api.thedogapi.com/v1/breeds")
>>> response.text
'[{...,"id":1,"name":"Affenpinscher",...}]'

I bet you’re already thinking about different ways that you can use these APIs to make some cute side project, and that’s the great thing about APIs. Once you start using them, there’s nothing stopping you from turning a hobby or passion into a fun project.

Before you move forward, one thing you need to know about endpoints is the difference between http:// and https://. In a nutshell, HTTPS is the encrypted version of HTTP, making all traffic between the client and the server much safer. When consuming public APIs, you should definitely stay away from sending any private or sensitive information to http:// endpoints and use only those APIs that provide a secure https:// base URL.

For more information on why it’s important to stick to HTTPS when browsing online, check out Exploring HTTPS With Python.

In the next section, you’ll dig a bit further into the main components of an API call.

Request and Response

As you very briefly read above, all interactions between a client—in this case, your Python console—and an API are split into a request and a response:

  • Requests contain relevant data regarding your API request call, such as the base URL, the endpoint, the method used, the headers, and so on.
  • Responses contain relevant data returned by the server, including the data or content, the status code, and the headers.

Using the Cat API again, you can drill down a bit more into what exactly is inside the Request and Response objects:

>>>
>>> response = requests.get("https://api.thecatapi.com/v1/breeds")
>>> response
<Response [200]>
>>> response.status_code
200
>>> response.text
'[{"weight":{"imperial":"7  -  10","metric":"3 - 5"},
"id":"abys","name":"Abyssinian","origin":"Egypt",
"temperament":"Active, Energetic, Independent, Intelligent, Gentle",...}]'
>>> response.headers
{'content-type': 'application/json; charset=utf-8',
'x-response-time': '1ms',  'Date': 'Mon, 24 Jul 2023 12:37:59 GMT',
'Server': 'Google Frontend', 'Content-Length': '76734', ...}

>>> response.request
<PreparedRequest [GET]>
>>> request = response.request
>>> request.url
'https://api.thecatapi.com/v1/breeds'
>>> request.path_url
'/v1/breeds'
>>> request.method
'GET'
>>> request.headers
{'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate',
'Accept': '*/*', 'Connection': 'keep-alive'}

Here, you’ve accessed a few of the most important attributes that are available for Request and Response objects.

You’ll learn more about some of these attributes in this tutorial, but if you want to dig even further, then you can check Mozilla’s documentation on HTTP messages for a more in-depth explanation of each attribute.

Status Codes

Status codes are one of the most important pieces of information to look for in any API response. They tell you if your request was successful, if it’s missing data, if it’s missing credentials, and so on.

With time, you’ll recognize the different status codes without help. But for now, here’s a list with some of the most common status codes that you’ll find:

Status code Description
200 OK Your request was successful!
201 Created Your request was accepted, and the resource was created.
400 Bad Request Your request is either wrong or missing some information.
401 Unauthorized Your request requires some additional permissions.
404 Not Found The requested resource doesn’t exist.
405 Method Not Allowed The endpoint doesn’t allow for that specific HTTP method.
500 Internal Server Error Your request wasn’t expected and probably broke something on the server side.

You saw 200 OK earlier in the examples that you executed, and you might even recognize 404 Not Found from browsing the Web.

You can check the status of a response using .status_code and .reason. The requests library also prints the status code in the representation of the Response object:

>>>
>>> response = requests.get("https://api.thecatapi.com/v1/breeds")
>>> response
<Response [200]>
>>> response.status_code
200