Python API Basics
About 5 minutes
An API call (Application Programming Interface call) is how programs access external services and data. When using AI services and web services with Python, APIs are an essential skill. With the requests library, you can call an API and process the results in just a few lines of code.
HTTP Methods Basics
Section titled “HTTP Methods Basics”APIs exchange data over HTTP (the same protocol used by web browsers). Learn the key HTTP methods:
| Method | Purpose | Example |
|---|---|---|
| GET | Retrieve data | Get user information, fetch article list |
| POST | Create new data | Send a message, upload a file |
| PUT | Update data (full replacement) | Update profile information |
| PATCH | Partially update data | Change only the name field |
| DELETE | Delete data | Remove a post |
Calls to AI service APIs (Claude, OpenAI, etc.) almost always use POST.
Installing the requests Library
Section titled “Installing the requests Library”pip install requestsVerify the installation:
import requests
print(requests.__version__) # e.g., 2.31.0GET Requests: Retrieving Data
Section titled “GET Requests: Retrieving Data”JSONPlaceholder is a free API for learning and testing. You can send real requests to it.
import requests
# Send a GET request
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
# Check the HTTP status code
print(response.status_code) # 200 (success)
# Receive the JSON data as a Python dictionary
data = response.json()
print(data)
# {
# 'userId': 1,
# 'id': 1,
# 'title': 'sunt aut facere repellat...',
# 'body': 'quia et suscipit...'
# }
# Extract specific fields
print(data["title"])
print(data["body"])Adding Query Parameters
Section titled “Adding Query Parameters”You can filter or search results by appending ?key=value to the URL. Use the params argument in requests:
import requests
# Use params instead of manually building the URL
# Actual URL: https://jsonplaceholder.typicode.com/posts?userId=1
response = requests.get(
"https://jsonplaceholder.typicode.com/posts",
params={"userId": 1}
)
posts = response.json()
print(f"Number of posts retrieved: {len(posts)}")
for post in posts[:3]: # Show first 3
print(f" - {post['title'][:40]}...")POST Requests: Sending Data
Section titled “POST Requests: Sending Data”import requests
# Define the data to send as a dictionary
new_post = {
"title": "Python API Basics",
"body": "Learn how to call APIs using the requests library",
"userId": 1
}
# Send a POST request (using json= auto-sets Content-Type)
response = requests.post(
"https://jsonplaceholder.typicode.com/posts",
json=new_post
)
print(response.status_code) # 201 (created)
created = response.json()
print(f"Created ID: {created['id']}")json= versus data=
Section titled “json= versus data=”| Argument | Content-Type | Use Case |
|---|---|---|
json=dict | application/json | REST APIs (AI services, etc.) |
data=dict | application/x-www-form-urlencoded | Same format as HTML forms |
AI APIs almost always use json=.
Error Handling
Section titled “Error Handling”APIs do not always succeed. Implement proper error handling:
Checking HTTP Status Codes
Section titled “Checking HTTP Status Codes”import requests
response = requests.get("https://jsonplaceholder.typicode.com/posts/999")
if response.status_code == 200:
print("Success:", response.json())
elif response.status_code == 404:
print("Not found (404)")
elif response.status_code == 429:
print("Rate limit reached (429). Please wait before retrying.")
elif response.status_code >= 500:
print(f"Server error ({response.status_code})")
else:
print(f"Error: {response.status_code}")Using raise_for_status()
Section titled “Using raise_for_status()”A more concise error checking approach:
import requests
try:
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
response.raise_for_status() # Raises an exception for 4xx/5xx status codes
data = response.json()
print(data["title"])
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e}")
except requests.exceptions.ConnectionError:
print("Network connection error. Please check your internet connection.")
except requests.exceptions.Timeout:
print("Timeout. The server took too long to respond.")
except requests.exceptions.RequestException as e:
print(f"Unexpected error: {e}")Setting a Timeout
Section titled “Setting a Timeout”import requests
# timeout=(connect_timeout_seconds, read_timeout_seconds)
response = requests.get(
"https://jsonplaceholder.typicode.com/posts/1",
timeout=(5, 30) # 5 seconds to connect, 30 seconds to read
)Without a timeout, your program will wait forever if the server does not respond. Always set one.
Headers and Authentication
Section titled “Headers and Authentication”Most APIs require authentication. Include an API key in the request headers:
import requests
import os
# Read API key from environment variable (never write it directly in code)
api_key = os.environ.get("MY_API_KEY")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"User-Agent": "MyApp/1.0" # Application identifier (optional)
}
response = requests.get(
"https://api.example.com/data",
headers=headers,
timeout=10
)The pattern of prefixing the key with "Bearer " (Bearer authentication) is the standard format used by many REST APIs including AI APIs.
Practical Example: Calling a Public API
Section titled “Practical Example: Calling a Public API”Using the GitHub public API to retrieve repository information:
import requests
import json
def get_github_repo_info(owner: str, repo: str) -> dict | None:
"""Retrieve basic information for a GitHub repository"""
url = f"https://api.github.com/repos/{owner}/{repo}"
headers = {
"Accept": "application/vnd.github.v3+json",
"User-Agent": "python-api-tutorial"
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if response.status_code == 404:
print(f"Repository not found: {owner}/{repo}")
else:
print(f"HTTP error: {e}")
return None
except requests.exceptions.RequestException as e:
print(f"Connection error: {e}")
return None
def display_repo_info(info: dict) -> None:
"""Display repository information in a readable format"""
print(f"Repository: {info['full_name']}")
print(f"Description: {info.get('description', '(no description)')}")
print(f"Stars: {info['stargazers_count']:,}")
print(f"Forks: {info['forks_count']:,}")
print(f"Primary language: {info.get('language', 'Unknown')}")
print(f"Last updated: {info['updated_at'][:10]}")
# Run it
info = get_github_repo_info("anthropics", "anthropic-sdk-python")
if info:
display_repo_info(info)Example output:
Repository: anthropics/anthropic-sdk-python
Description: The official Python library for the Anthropic API
Stars: 4,123
Forks: 456
Primary language: Python
Last updated: 2026-05-10Using Sessions for Efficiency
Section titled “Using Sessions for Efficiency”When making multiple requests to the same host, using requests.Session reuses the TCP connection and improves performance:
import requests
# Create a session
with requests.Session() as session:
# Set headers shared across all requests in this session
session.headers.update({
"Authorization": "Bearer my-api-key",
"Content-Type": "application/json"
})
# Send multiple requests using the same session
response1 = session.get("https://api.example.com/users/1")
response2 = session.get("https://api.example.com/users/2")
response3 = session.post("https://api.example.com/messages", json={"text": "hello"})Summary
Section titled “Summary”requests.get()retrieves data;.json()converts the response to a Python dictionaryrequests.post(url, json=data)sends data- Use
raise_for_status()andtry/exceptto handle errors properly - Read API keys from environment variables; never write them directly in code
- Always set a
timeout - Use
Sessionfor multiple requests to the same host
As a next step, learn more advanced API response processing in JSON Processing in Python, then move on to AI API calls in Python AI SDK in Practice.
Q: What is the difference between requests and urllib.request?
A: urllib.request is part of the Python standard library and requires no additional installation, but its API is verbose. requests is a third-party library that provides a simpler, more intuitive API. In practice, requests (or async httpx) is widely used.
Q: What should I do when a rate limit (HTTP 429) is hit?
A: A 429 status code is returned. The Retry-After header may specify a wait time. Use time.sleep() to wait and then retry, or use a retry library like tenacity.
Q: How do I call APIs asynchronously?
A: Combine asyncio with the httpx library. This is effective when making multiple API calls in parallel or when integrating with async frameworks like FastAPI.
Q: What should I do if I get an HTTPS certificate error?
A: This can happen when using a corporate proxy or custom CA certificate. Specify the certificate with requests.get(url, verify="/path/to/ca-bundle.crt") or consult your IT department. Never use verify=False in production.
See the references for the external specifications and background sources used on this page.[1][2][3][4]