Skip to Content
Course content

275: Handling JSON APIs with requests

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've been wanting to build a small tool to track some gaming stats, and that means I need to get comfortable talking to external APIs. Most of the web speaks JSON these days, and while we've touched on dictionaries and lists, actually pulling that data over the wire is where things usually get messy. Let's dive in.

Wait, where is my data?

I'll start with something simple. I want to get some data about Pikachu from the PokeAPI. I've got the requests library installed, so I'll just fire off a get request and see what happens.

import requests

response = requests.get('https://pokeapi.co/api/v2/pokemon/pikachu')
print(response)

If you run this, you won't see Pikachu's height or weight. You'll see <Response [200]>. This is a common point of confusion. The requests.get() method doesn't return the data itself; it returns a Response object. The [200] is just the HTTP status code telling us "Okay, everything went fine." The actual data is tucked away inside that object.

Strings aren't dictionaries

Naturally, my first instinct is to just print the response to see what's inside. I'll try accessing the .text attribute, which gives me the raw body of the response.

print(response.text)

This works, but it's a nightmare. It prints a massive, unformatted wall of text. Now, I know this is JSON, which looks exactly like a Python dictionary, but response.text is just one giant string. If I try to do something like response.text['name'], Python is going to throw a TypeError because you can't use a string key to index into a string.

The .json() shortcut

I could use the built-in json module to parse that string, but requests has a much cleaner way to handle this. There's a built-in method called .json() that does the heavy lifting for us.

data = response.json()
print(data['name']) # Output: pikachu
print(data['weight']) # Output: 60

Much better. By calling .json(), the library takes that raw string, parses it, and converts it directly into a Python dictionary (or a list, depending on the API). Now I can navigate the data using the standard key-lookup syntax we've used before. I noticed the API nests its data quite deeply, though. If I want to find Pikachu's first ability, I have to chain my lookups:

# Abilities is a list, so we grab the first element [0], 
# then the 'ability' dictionary, then the 'name' key.
first_ability = data['abilities'][0]['ability']['name']
print(f"Pikachu's primary ability is {first_ability}.")

When the API says "No"

So far, everything is sunshine and rainbows because I'm using a valid URL. But in a real app, things break. What happens if I search for a Pokémon that doesn't exist?

response = requests.get('https://pokeapi.co/api/v2/pokemon/not-a-real-pokemon')
data = response.json() # This might crash or return an error message

The problem here is that requests doesn't automatically raise an exception if the server returns a 404 (Not Found) or a 500 (Server Error). It just gives you the response object with that error code. If I call .json() on a 404 page that happens to return HTML instead of JSON, my program will crash with a JSONDecodeError.

To fix this, I'll use raise_for_status(). This method checks the status code and immediately throws an exception if the request wasn't successful. It's a much cleaner way to handle errors than writing if response.status_code == 200: every single time.

try:
    response = requests.get('https://pokeapi.co/api/v2/pokemon/not-a-real-pokemon')
    response.raise_for_status() 
    data = response.json()
except requests.exceptions.HTTPError as err:
    print(f"HTTP error occurred: {err}")
except Exception as err:
    print(f"An unexpected error occurred: {err}")

Now the code is robust. It tries to get the data, ensures the server actually found the resource, and handles the failure gracefully if it didn't.




📋 Practical Task

Build a Pokémon Ability Explorer

Your task is to write a script that allows a user to input the name of a Pokémon and prints out a formatted list of all its abilities.

Requirements:

  • Prompt the user for a Pokémon name (e.g., "charizard" or "ditto").
  • Use requests.get() to fetch data from https://pokeapi.co/api/v2/pokemon/{name}.
  • Implement response.raise_for_status() within a try/except block to handle cases where the user enters a name that doesn't exist.
  • Parse the JSON response and loop through the abilities list to print each ability's name in a clean format (e.g., "Ability: Blaze").
  • If an error occurs, print a user-friendly message explaining that the Pokémon could not be found.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.