advanced Step 17 of 20

Working with APIs

Python Programming

Working with APIs

APIs (Application Programming Interfaces) are the backbone of modern software, enabling different applications to communicate with each other. REST APIs, accessed over HTTP, are the most common type you will encounter. Whether you are fetching weather data, posting to social media, processing payments, or integrating third-party services, you need to know how to make HTTP requests and handle responses. Python's requests library makes this task straightforward and enjoyable, providing a clean interface for all types of HTTP operations.

Making GET Requests

import requests

# Simple GET request
response = requests.get("https://jsonplaceholder.typicode.com/posts/1")

# Check status code
print(response.status_code)   # 200
print(response.ok)            # True (status code < 400)

# Parse JSON response
data = response.json()
print(data["title"])
print(data["body"])

# Response headers
print(response.headers["Content-Type"])

# GET with query parameters
params = {"userId": 1, "_limit": 5}
response = requests.get(
    "https://jsonplaceholder.typicode.com/posts",
    params=params
)
posts = response.json()
for post in posts:
    print(f"  {post['id']}: {post['title'][:50]}")

POST, PUT, PATCH, DELETE

# POST — create a new resource
new_post = {
    "title": "My New Post",
    "body": "This is the content of my post.",
    "userId": 1
}
response = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json=new_post   # Automatically sets Content-Type and serializes
)
print(response.status_code)  # 201 (Created)
created = response.json()
print(f"Created post with ID: {created['id']}")

# PUT — replace entire resource
updated_post = {
    "id": 1,
    "title": "Updated Title",
    "body": "Updated body content.",
    "userId": 1
}
response = requests.put(
    "https://jsonplaceholder.typicode.com/posts/1",
    json=updated_post
)

# PATCH — partial update
response = requests.patch(
    "https://jsonplaceholder.typicode.com/posts/1",
    json={"title": "Just Update the Title"}
)

# DELETE
response = requests.delete(
    "https://jsonplaceholder.typicode.com/posts/1"
)
print(response.status_code)  # 200

Headers and Authentication

# Custom headers
headers = {
    "Authorization": "Bearer your_api_token_here",
    "Accept": "application/json",
    "User-Agent": "MyApp/1.0"
}
response = requests.get(
    "https://api.example.com/data",
    headers=headers
)

# Basic authentication
response = requests.get(
    "https://api.example.com/protected",
    auth=("username", "password")
)

# Session — persist settings across requests
session = requests.Session()
session.headers.update({
    "Authorization": "Bearer token123",
    "Accept": "application/json"
})

# All requests in this session include the headers
r1 = session.get("https://api.example.com/users")
r2 = session.get("https://api.example.com/posts")
session.close()

Error Handling and Timeouts

import requests
from requests.exceptions import (
    ConnectionError, Timeout, HTTPError, RequestException
)

def fetch_data(url, max_retries=3):
    for attempt in range(1, max_retries + 1):
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()  # Raises HTTPError for 4xx/5xx
            return response.json()

        except Timeout:
            print(f"Attempt {attempt}: Request timed out")
        except ConnectionError:
            print(f"Attempt {attempt}: Connection failed")
        except HTTPError as e:
            print(f"HTTP error: {e.response.status_code}")
            if e.response.status_code == 404:
                return None  # Resource not found, don't retry
            if e.response.status_code >= 500:
                print("Server error, retrying...")
                continue
            return None
        except RequestException as e:
            print(f"Request failed: {e}")
            return None

    print("All retries exhausted")
    return None

data = fetch_data("https://jsonplaceholder.typicode.com/posts/1")
if data:
    print(data["title"])
Pro tip: Always set a timeout on your requests to prevent your program from hanging indefinitely if the server is unresponsive. A timeout of 10-30 seconds is reasonable for most APIs. Also, use response.raise_for_status() to automatically raise an exception for HTTP error codes (4xx and 5xx).

Key Takeaways

  • Use the requests library for HTTP operations: get(), post(), put(), patch(), and delete().
  • Pass json=data for JSON payloads and params=dict for query parameters.
  • Always handle errors with try/except and set timeouts to prevent hanging requests.
  • Use response.raise_for_status() to automatically detect HTTP errors (4xx/5xx status codes).
  • Use requests.Session() to persist headers and authentication across multiple requests efficiently.