Lesson 2 of 8
response.json() hands you an ordinary Python dictionary or list. From there it's all Module 3
skills — but API data is messier than data you built yourself, so a few habits matter.
import requests
response = requests.get("https://api.github.com/users/python")
data = response.json()
print(type(data))
print(data["name"])
print(data["public_repos"])
.json() versus json.loads()
response.json() is a convenience for json.loads(response.text). Same result; use .json()
with requests.
It raises if the body isn't valid JSON — which happens when a server returns an HTML error page instead of data. Lesson 8.5 handles that.
Navigating nested data
Real responses nest several levels deep. Read the path left to right, exactly as in lesson 3.8:
import json
body = '''{
"count": 2,
"results": [
{"name": "Ada", "address": {"city": "London"}},
{"name": "Grace", "address": {"city": "New York"}}
]
}'''
data = json.loads(body)
print(data["count"])
print(data["results"][0]["name"])
print(data["results"][0]["address"]["city"])
for person in data["results"]:
print(f"{person['name']} - {person['address']['city']}")
Missing keys are the norm
This is the big difference from your own data: an API can omit a field at any time. Optional
fields are missing rather than null, and APIs change without warning.
import json
data = json.loads('{"name": "Ada"}')
print(data["email"])
That raises KeyError. Use .get() with a default instead — the lesson 3.5 habit, now
essential:
import json
data = json.loads('{"name": "Ada"}')
print(data.get("email"))
print(data.get("email", "no email provided"))
For nested paths, chain carefully. data.get("address", {}).get("city") works because the
fallback {} still has a .get():
import json
with_address = json.loads('{"address": {"city": "London"}}')
without = json.loads('{"name": "Ada"}')
print(with_address.get("address", {}).get("city", "unknown"))
print(without.get("address", {}).get("city", "unknown"))
Extracting what you need
Don't pass raw API responses around your program. Pull out the fields you care about into your own shape — then an API change breaks in one place instead of everywhere:
import json
body = '''{"results": [
{"name": "Ada", "public_repos": 8, "extra": "ignore me"},
{"name": "Grace", "public_repos": 3, "extra": "ignore me"}
]}'''
raw = json.loads(body)
people = [
{"name": r["name"], "repos": r.get("public_repos", 0)}
for r in raw["results"]
]
print(people)
print(sum([p["repos"] for p in people]))
Exploring an unfamiliar response
When you don't know the shape yet, print the keys first:
import json
data = json.loads('{"name": "Ada", "id": 1, "tags": ["python"]}')
print(sorted(data.keys()))
print(json.dumps(data, indent=2))
json.dumps(data, indent=2) pretty-prints it — the fastest way to see the structure.
Try it yourself
Parse a nested response, handle a missing field, and reshape it.
Checkpoint
response.json()returns plain Python dicts and lists.- Navigate nested data left to right, as with any nested structure.
- Assume fields can be missing — prefer
.get(key, default)overdata[key]. - Chain
.get("a", {}).get("b")for nested optional paths. - Extract into your own shape so an API change breaks one place, not many.
Questions about this lesson
Log in to ask a question.