The Python requests library is often called “HTTP for Humans” - and for good reason! It makes interacting with web services incredibly straightforward. Today, we’ll explore how to use this powerful library to interact with web APIs.
Making a Simple GET Request
Let’s start with a basic example that fetches data from the JSONPlaceholder API, a free fake API for testing and prototyping:
import requests
# Make a GET request to fetch a user
response = requests.get('https://jsonplaceholder.typicode.com/users/1')
# Check if the request was successful
if response.status_code == 200:
# Parse the JSON response
user_data = response.json()
print(f"User: {user_data['name']}")
print(f"Email: {user_data['email']}")
print(f"Company: {user_data['company']['name']}")
else:
print(f"Error: {response.status_code}")
Posting Data to an API
Here’s how you can make a POST request to create a new resource:
import requests
import json
# Data to send in the POST request
new_post = {
'title': 'My New Blog Post',
'body': 'This is the content of my post.',
'userId': 1
}
# Make a POST request
response = requests.post(
'https://jsonplaceholder.typicode.com/posts',
json=new_post, # requests will automatically JSON-encode this dict
headers={
'Content-Type': 'application/json',
}
)
if response.status_code == 201: # 201 means "Created"
created_post = response.json()
print("Post created successfully!")
print(f"Post ID: {created_post['id']}")
print(f"Title: {created_post['title']}")
else:
print(f"Error: {response.status_code}")
Error Handling Best Practices
Here’s a more robust example that includes proper error handling:
import requests
from requests.exceptions import RequestException
def fetch_data(url: str) -> dict | None:
"""Fetches JSON data from a specified URL using HTTP GET request.
Args:
url (str): The URL endpoint to fetch data from.
Returns:
dict: The JSON response data if successful.
None: If any error occurs during the request.
Raises:
requests.exceptions.HTTPError: If the HTTP response indicates an error (4xx, 5xx).
requests.exceptions.ConnectionError: If connection to the server fails.
requests.exceptions.Timeout: If the request exceeds 5 second timeout.
requests.exceptions.RequestException: For other request-related errors.
Note:
All exceptions are caught internally and logged to stdout. The function
will return None instead of raising exceptions.
"""
try:
response = requests.get(url, timeout=5) # Add timeout of 5 seconds
response.raise_for_status() # Raises an HTTPError for bad responses (4xx, 5xx)
return response.json()
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred: {http_err}")
except requests.exceptions.ConnectionError as conn_err:
print(f"Error connecting to the server: {conn_err}")
except requests.exceptions.Timeout as timeout_err:
print(f"Timeout error: {timeout_err}")
except requests.exceptions.RequestException as err:
print(f"An error occurred: {err}")
return None
# Example usage
data = fetch_data('https://jsonplaceholder.typicode.com/users/1')
if data:
print(f"Successfully fetched data for user: {data['name']}")
Why This Matters
Using the requests
library properly can help you:
- Handle API interactions robustly
- Deal with errors gracefully
- Create maintainable code
- Save time compared to using lower-level libraries
Remember to always:
- Check status codes
- Handle exceptions appropriately
- Set timeouts for your requests
- Use proper headers when needed
The examples above demonstrate these best practices while keeping the code clean and readable.