Working with APIs
Call REST APIs, read JSON responses, handle pagination, and build real programs powered by live internet data.
"An API is a restaurant menu: you don't go into the kitchen, you just say what you want and get back what you ordered. JSON is how the restaurant writes the receipt."
— ShuraiWhat is a REST API?
A REST API is a web service you talk to by sending HTTP requests to URLs (called endpoints). Each endpoint does one thing: get a list, create a record, update, or delete. The server replies with data — almost always in JSON format:
GET
Read
Fetch data. Never changes anything on the server.
POST
Create
Send data to create a new resource.
PUT
Update
Replace an existing resource entirely.
DELETE
Delete
Remove a resource.
Calling a Real API — Step by Step
Let’s use JSONPlaceholder — a free practice API that mimics a real to-do app:
import requests
# 1. GET — fetch all todos
resp = requests.get("https://jsonplaceholder.typicode.com/todos")
todos = resp.json()
print(f"Total todos: {len(todos)}") # 200
# 2. GET one item by ID
todo = requests.get("https://jsonplaceholder.typicode.com/todos/1").json()
print(todo)
# {'userId': 1, 'id': 1, 'title': 'delectus aut autem', 'completed': False}
# 3. POST — create a new todo
new_todo = {"title": "Learn Python APIs", "completed": False, "userId": 1}
resp = requests.post("https://jsonplaceholder.typicode.com/todos", json=new_todo)
print(resp.status_code, resp.json()) # 201 {'id': 201, 'title': 'Learn...}
# 4. DELETE
resp = requests.delete("https://jsonplaceholder.typicode.com/todos/1")
print(resp.status_code) # 200 — deleted
Parsing Nested JSON Like a Pro
Real API responses are often deeply nested. Treat the JSON like a Python dict — because it is one:
import requests
resp = requests.get("https://api.github.com/repos/python/cpython")
repo = resp.json()
# Navigate nested keys just like a dict
print(repo["full_name"]) # python/cpython
print(repo["stargazers_count"]) # 60000+
print(repo["owner"]["login"]) # python — nested dict
print(repo.get("homepage", "N/A")) # use .get() for optional keys
Handling Pagination
Most APIs return results in pages (e.g. 100 items per page). Loop through pages until you have everything:
import requests
def get_all_users():
all_users = []
page = 1
while True:
resp = requests.get(
"https://reqres.in/api/users",
params={"page": page},
timeout=5
)
data = resp.json()
all_users.extend(data["data"])
if page >= data["total_pages"]:
break
page += 1
return all_users
users = get_all_users()
print(f"Total users: {len(users)}")
Real Example — Currency Converter
import requests
def convert_currency(amount, from_cur, to_cur):
"""Convert amount from one currency to another."""
url = f"https://api.frankfurter.app/latest?from={from_cur}&to={to_cur}"
try:
resp = requests.get(url, timeout=5)
resp.raise_for_status()
rate = resp.json()["rates"][to_cur]
result = amount * rate
print(f"{amount} {from_cur} = {result:.2f} {to_cur} (rate: {rate})")
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
convert_currency(1000, "INR", "USD")
convert_currency(100, "USD", "EUR")
convert_currency(500, "GBP", "JPY")
Great free APIs with no key required: Open-Meteo (weather), Frankfurter.app (currency), JSONPlaceholder (fake CRUD), GitHub API (repos/users), REST Countries (country data). For premium APIs, look for a free tier — most have one.
"Once you understand REST + JSON, every app on the internet is a data source. News, sports scores, stock prices, maps — they all speak the same language."
— Shurai🧠 Quiz — Q1
What does the GET HTTP verb do?
🧠 Quiz — Q2
An API returns JSON. After calling data = resp.json(), how do you access a nested field owner.login?
🧠 Quiz — Q3
Why should you use .get("key", default) when reading JSON response fields?
🧠 Quiz — Q4
What does pagination mean in the context of APIs?