The requests Library
requests is the de-facto standard for making HTTP requests in Python. Clean, intuitive API that abstracts away the complexity of urllib.
# pip install requests
import requests
# GET request
response = requests.get("https://api.github.com/users/python")
print(response.status_code) # 200
print(response.json()) # Parse JSON response
print(response.text) # Raw text
print(response.headers) # Response headers
print(response.url) # Final URL (after redirects)
# POST request with JSON body
response = requests.post(
"https://httpbin.org/post",
json={"name": "Alice", "age": 30} # Automatically sets Content-Type
)
# Request with headers
headers = {"Authorization": "Bearer mytoken", "Accept": "application/json"}
response = requests.get("https://api.example.com/data", headers=headers)
# Query parameters
params = {"q": "python", "sort": "stars", "per_page": 10}
response = requests.get("https://api.github.com/search/repositories", params=params)
# URL becomes: ?q=python&sort=stars&per_page=10
# PUT, PATCH, DELETE
requests.put("https://api.example.com/items/1", json={"name": "Updated"})
requests.patch("https://api.example.com/items/1", json={"name": "Patched"})
requests.delete("https://api.example.com/items/1")Error Handling
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
# Check status
response = requests.get("https://api.example.com/data")
response.raise_for_status() # Raises HTTPError for 4xx/5xx
# Or check manually
if response.status_code == 200:
data = response.json()
elif response.status_code == 404:
print("Resource not found")
else:
print(f"Error: {response.status_code}")
# Handle network errors
try:
response = requests.get("https://api.example.com/data", timeout=5)
response.raise_for_status()
data = response.json()
except Timeout:
print("Request timed out")
except ConnectionError:
print("Connection failed")
except requests.HTTPError as e:
print(f"HTTP error: {e.response.status_code}")Sessions and Authentication
# Session: reuse connection, persist headers/cookies
session = requests.Session()
session.headers.update({"Authorization": "Bearer token123"})
# All requests in session use the same headers
r1 = session.get("https://api.example.com/users")
r2 = session.get("https://api.example.com/items")
# Basic auth
response = requests.get("https://api.example.com", auth=("username", "password"))
# Bearer token
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.get("https://api.example.com/protected", headers=headers)
# File upload
with open("photo.jpg", "rb") as f:
files = {"file": ("photo.jpg", f, "image/jpeg")}
response = requests.post("https://api.example.com/upload", files=files)
# Download file
response = requests.get("https://example.com/large-file.zip", stream=True)
with open("file.zip", "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)Practical API Client
# Building a reusable API client
class APIClient:
def __init__(self, base_url, api_key):
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({"X-API-Key": api_key})
def get(self, path, **kwargs):
return self._request("GET", path, **kwargs)
def post(self, path, data=None, **kwargs):
return self._request("POST", path, json=data, **kwargs)
def _request(self, method, path, **kwargs):
url = f"{self.base_url}/{path.lstrip('/')}"
try:
response = self.session.request(method, url, timeout=10, **kwargs)
response.raise_for_status()
return response.json()
except requests.HTTPError as e:
raise RuntimeError(f"API error {e.response.status_code}: {e.response.text}")
client = APIClient("https://api.example.com", "my-api-key")
users = client.get("/users")
new_user = client.post("/users", {"name": "Alice"})Key Takeaways
- requests.get/post/put/delete: simple single-request functions
- Session for multiple requests: reuses connection, shares headers
- response.raise_for_status(): auto-raise on 4xx/5xx
- Always set timeout: default is to wait forever
- stream=True for large downloads: don't load everything into memory
Practice Exercises
- Fetch the list of Python repositories from GitHub API (search/repositories?q=language:python&sort=stars). Print the top 10 by star count.
- Build a currency converter using a free exchange rate API (exchangerate-api.com has a free tier).
- Build a reusable API client class with retry logic and exponential backoff.