JSON APIs
Consuming and producing JSON APIs in Python — requests, parsing, error handling
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
JSON (JavaScript Object Notation) is the standard data format for web APIs. Here's how to work with it effectively in Python.
Calling APIs with httpx (async-capable):
python import httpx # Sync with httpx.Client() as client: response = client.get("https://api.github.com/users/octocat") response.raise_for_status() # raises HTTPStatusError on 4xx/5xx user = response.json() # dict # Async async with httpx.AsyncClient() as client: response = await client.get("https://api.github.com/users/octocat") user = response.json()
Sending JSON:
python data = {"name": "Alice", "email": "alice@example.com"} response = httpx.post( "https://api.example.com/users", json=data, # auto-sets Content-Type: application/json headers={"Authorization": f"Bearer {token}"}, )
Robust error handling:
python import httpx def get_user(user_id: int) -> dict | None: try: r = httpx.get(f"https://api.example.com/users/{user_id}", timeout=5.0) r.raise_for_status() return r.json() except httpx.TimeoutException: print("Request timed out") except httpx.HTTPStatusError as e: print(f"HTTP {e.response.status_code}: {e.response.text}") except httpx.RequestError as e: print(f"Network error: {e}") return None
json module for serialization:
python import json obj = {"name": "Alice", "score": 95.5, "active": True} text = json.dumps(obj, indent=2) # Python → JSON string back = json.loads(text) # JSON string → Python
Examples
Paginated API consumption
Paginating an API — yield from to flatten pages into a single stream
import httpx
from typing import Iterator
def iter_all_pages(base_url: str, token: str) -> Iterator[dict]:
page = 1
while True:
r = httpx.get(
base_url,
params={"page": page, "per_page": 100},
headers={"Authorization": f"Bearer {token}"},
timeout=10.0,
)
r.raise_for_status()
data = r.json()
if not data:
break
yield from data
page += 1
for user in iter_all_pages("https://api.example.com/users", token):
print(user["email"])Structured response parsing with dataclasses
Parsing raw API dicts into typed dataclasses — cleaner than working with raw dicts everywhere
from dataclasses import dataclass
import httpx
@dataclass
class Repo:
name: str
stars: int
language: str | None
@classmethod
def from_api(cls, data: dict) -> "Repo":
return cls(
name=data["name"],
stars=data["stargazers_count"],
language=data.get("language"),
)
r = httpx.get("https://api.github.com/users/python/repos")
repos = [Repo.from_api(item) for item in r.json()]
top = sorted(repos, key=lambda r: r.stars, reverse=True)[:5]How well did you understand this?
Next in Web & HTTP
Authentication & Headers