Here's how to make HTTP requests in Python, from simple to advanced.

Install: pip install requests

Basic Requests

import requests
 
# GET request
response = requests.get("https://api.example.com/users")
print(response.status_code)  # 200
print(response.json())       # Parse JSON response
 
# POST request
response = requests.post(
    "https://api.example.com/users",
    json={"name": "Alice", "email": "alice@example.com"}
)
 
# Other methods
requests.put(url, json=data)
requests.patch(url, json=data)
requests.delete(url)
requests.head(url)

Query Parameters

# Add query string parameters
response = requests.get(
    "https://api.example.com/search",
    params={"q": "python", "page": 1, "limit": 10}
)
# URL: https://api.example.com/search?q=python&page=1&limit=10

Headers

headers = {
    "Authorization": "Bearer your-token",
    "Content-Type": "application/json",
    "User-Agent": "MyApp/1.0"
}
 
response = requests.get(url, headers=headers)
 
# Access response headers
print(response.headers["Content-Type"])

Request Body

# JSON body (most common)
requests.post(url, json={"key": "value"})
 
# Form data
requests.post(url, data={"field": "value"})
 
# Raw data
requests.post(url, data="raw content", headers={"Content-Type": "text/plain"})

Authentication

# Basic auth
requests.get(url, auth=("username", "password"))
 
# Bearer token
requests.get(url, headers={"Authorization": "Bearer token"})
 
# Custom auth
from requests.auth import AuthBase
 
class TokenAuth(AuthBase):
    def __init__(self, token):
        self.token = token
    
    def __call__(self, r):
        r.headers["X-API-Key"] = self.token
        return r
 
requests.get(url, auth=TokenAuth("my-api-key"))

Response Handling

response = requests.get(url)
 
# Status
response.status_code      # 200
response.ok               # True if 200-299
response.raise_for_status()  # Raises HTTPError if not ok
 
# Content
response.text             # String content
response.json()           # Parse JSON
response.content          # Raw bytes
 
# Headers
response.headers          # Response headers
 
# Request info
response.url              # Final URL (after redirects)
response.request.headers  # Request headers sent

Timeouts

# Always use timeouts!
response = requests.get(url, timeout=10)  # 10 seconds
 
# Separate connect and read timeouts
response = requests.get(url, timeout=(3, 10))  # 3s connect, 10s read

Error Handling

import requests
 
try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    data = response.json()
except requests.exceptions.Timeout:
    print("Request timed out")
except requests.exceptions.ConnectionError:
    print("Connection failed")
except requests.exceptions.HTTPError as e:
    print(f"HTTP error: {e}")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")

Sessions

Persist settings across requests:

session = requests.Session()
session.headers.update({"Authorization": "Bearer token"})
 
# All requests use the same headers
session.get(url1)
session.get(url2)
 
# With context manager
with requests.Session() as session:
    session.get(url)

File Upload

# Upload file
with open("file.txt", "rb") as f:
    response = requests.post(url, files={"file": f})
 
# Multiple files
files = {
    "file1": open("file1.txt", "rb"),
    "file2": ("custom_name.txt", open("file2.txt", "rb"))
}
response = requests.post(url, files=files)

Download Files

# Small files
response = requests.get(url)
with open("file.txt", "wb") as f:
    f.write(response.content)
 
# Large files (streaming)
with requests.get(url, stream=True) as response:
    with open("large_file.zip", "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)

Using urllib (Standard Library)

from urllib.request import urlopen, Request
from urllib.parse import urlencode
import json
 
# Simple GET
with urlopen("https://api.example.com/data") as response:
    data = json.loads(response.read())
 
# With headers
request = Request(
    "https://api.example.com/data",
    headers={"Authorization": "Bearer token"}
)
with urlopen(request) as response:
    data = json.loads(response.read())
 
# POST with data
data = urlencode({"key": "value"}).encode()
request = Request("https://api.example.com/post", data=data)
with urlopen(request) as response:
    result = response.read()

Common Patterns

Retry logic

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
 
session = requests.Session()
retries = Retry(
    total=3,
    backoff_factor=0.5,
    status_forcelist=[500, 502, 503, 504]
)
session.mount("https://", HTTPAdapter(max_retries=retries))
 
response = session.get(url)

API client class

class APIClient:
    def __init__(self, base_url, api_key):
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers["Authorization"] = f"Bearer {api_key}"
    
    def get(self, endpoint, **kwargs):
        return self.session.get(f"{self.base_url}{endpoint}", **kwargs)
    
    def post(self, endpoint, data, **kwargs):
        return self.session.post(f"{self.base_url}{endpoint}", json=data, **kwargs)
 
client = APIClient("https://api.example.com", "my-key")
users = client.get("/users").json()

Quick Reference

import requests
 
# Basic requests
requests.get(url)
requests.post(url, json=data)
 
# With options
requests.get(url,
    params={"key": "value"},     # Query string
    headers={"Auth": "token"},   # Headers
    timeout=10,                  # Timeout
    auth=("user", "pass"),       # Basic auth
)
 
# Response
response.status_code
response.json()
response.text
response.raise_for_status()
 
# Session
with requests.Session() as s:
    s.headers["Auth"] = "token"
    s.get(url)

Use requests for most HTTP work. It's simpler and handles edge cases better than urllib.

React to this post: