Most services expose data through HTTP APIs that return JSON. The popular requests library makes calls simple: requests.get(url, params=..., timeout=...).
Always set a timeout — without one, a slow server can hang your program forever. Call response.raise_for_status() to turn HTTP errors (404, 500) into exceptions, then response.json() to parse the body.
Use a requests.Session when making many calls to the same server: it reuses connections and lets you set shared headers (such as an API key) once. Keep API keys in environment variables, never in code.
pip install requestsimport os
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def get_user(session: requests.Session, user_id: int) -> dict:
response = session.get(f"{BASE_URL}/users/{user_id}", timeout=5)
response.raise_for_status()
return response.json()
def main() -> None:
with requests.Session() as session:
session.headers["Authorization"] = f"Bearer {os.environ.get('API_TOKEN', 'demo')}"
for user_id in [1, 2, 999]:
try:
user = get_user(session, user_id)
print(f"{user['name']} - {user['address']['city']}")
except requests.HTTPError as err:
print(f"user {user_id}: HTTP {err.response.status_code}")
except requests.RequestException as err:
print(f"user {user_id}: network problem: {err}")
if __name__ == "__main__":
main()Key points
- Always pass
timeout=to network calls. raise_for_status()turns HTTP error codes into exceptions.- Read secrets such as API keys from environment variables.
Exercise
Fetch the posts for user 1 from /posts?userId=1 using params={"userId": 1}, and print the five longest post titles. Add a retry: if a request fails with a network error, wait one second and try again up to three times.
Show solution
Try the exercise yourself first — then compare your approach with this one.
Pass query parameters with params= instead of building the URL by hand. The get_with_retry helper retries only network errors (not 404s), waiting a second between attempts, and re-raises after the third failure.
import time
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def get_with_retry(session: requests.Session, url: str, params: dict, attempts: int = 3) -> requests.Response:
for attempt in range(1, attempts + 1):
try:
response = session.get(url, params=params, timeout=5)
response.raise_for_status()
return response
except (requests.ConnectionError, requests.Timeout) as err:
if attempt == attempts:
raise
print(f"attempt {attempt} failed ({type(err).__name__}), retrying in 1s")
time.sleep(1)
raise AssertionError("unreachable")
def main() -> None:
with requests.Session() as session:
posts = get_with_retry(session, f"{BASE_URL}/posts", params={"userId": 1}).json()
longest = sorted(posts, key=lambda p: len(p["title"]), reverse=True)[:5]
for post in longest:
print(f"{len(post['title']):>3} {post['title']}")
if __name__ == "__main__":
main()