Python REST APIs
Learn how modern applications communicate through REST APIs. Understand resources, endpoints, HTTP methods, JSON, authentication, pagination, errors and how to build a practical Python API client.
Learning Objectives
REST APIs are one of the most common ways applications exchange information over the internet. By the end of this lesson, you will understand how REST APIs are designed and how Python applications consume them.
You will learn how to:
- Understand APIs and REST architecture.
- Work with API resources and endpoints.
- Use HTTP methods correctly.
- Exchange JSON data.
- Build GET, POST, PUT, PATCH and DELETE requests.
- Understand HTTP status codes.
- Work with request headers.
- Understand API authentication.
- Handle pagination and filtering.
- Handle API errors.
- Build a reusable Python API client.
- Apply REST concepts to ecommerce systems.
What Is an API?
API stands for Application Programming Interface.
An API provides a defined way for one software system to communicate with another software system.
For example, an ecommerce application might communicate with a payment service through an API.
Ecommerce Website
↓
API Request
↓
Payment Service
↓
API Response
↓
Ecommerce Website
Think of an API as a Contract
An API defines what requests can be made, what data should be supplied and what kind of response the client can expect.
What Is REST?
REST stands for Representational State Transfer.
REST is an architectural style for designing networked applications. REST APIs commonly use HTTP and represent information as resources.
A RESTful API generally uses:
- HTTP methods
- Resource-based URLs
- Stateless requests
- Standard HTTP status codes
- Representations such as JSON
Important Concept
REST is not a programming language and it is not a Python library. It is a way of designing APIs.
REST Resources
REST APIs commonly organize data around resources.
In an ecommerce application, resources might include:
/products
/customers
/orders
/categories
/reviews
A particular product could be represented as:
/products/101
Here, 101 identifies a specific product.
HTTP Methods
REST APIs use HTTP methods to communicate the intended operation.
Common REST Operations
- GET — retrieve resources
- POST — create a resource
- PUT — replace a resource
- PATCH — partially update a resource
- DELETE — remove a resource
GET /products
POST /products
GET /products/101
PUT /products/101
PATCH /products/101
DELETE /products/101
API URLs and Endpoints
An API endpoint is a specific URL through which a client interacts with a resource.
https://api.example.com/products
A versioned API might look like:
https://api.example.com/v1/products
A specific resource might be:
https://api.example.com/v1/products/25
Why API Versions Matter
API versions allow service providers to introduce changes while giving existing applications time to continue using an older interface.
JSON Data
REST APIs frequently use JSON to represent structured data.
{
"id": 101,
"name": "Laptop",
"price": 1200,
"stock": 15
}
Python can convert JSON responses into dictionaries and lists.
import requests
response = requests.get(
"https://example.com/api/products"
)
data = response.json()
print(data["name"])
A JSON array may become a Python list.
[
{
"id": 1,
"name": "Laptop"
},
{
"id": 2,
"name": "Phone"
}
]
GET Requests
GET is commonly used to retrieve resources.
import requests
url = "https://example.com/api/products"
response = requests.get(
url,
timeout=10
)
response.raise_for_status()
products = response.json()
for product in products:
print(product["name"])
This pattern is common when consuming an API:
Request
↓
Status Check
↓
JSON Parsing
↓
Python Data
↓
Application Logic
POST Requests
POST is commonly used to create a new resource.
import requests
product = {
"name": "Laptop",
"price": 1200,
"stock": 10
}
response = requests.post(
"https://example.com/api/products",
json=product,
timeout=10
)
print(response.status_code)
A successful resource creation commonly results in
status code 201 Created.
Important
The endpoint above is illustrative. A real API must document the exact URL, fields and authentication requirements.
PUT Requests
PUT is commonly associated with replacing an existing resource with a new representation.
import requests
updated_product = {
"name": "Laptop Pro",
"price": 1500,
"stock": 20
}
response = requests.put(
"https://example.com/api/products/101",
json=updated_product,
timeout=10
)
print(response.status_code)
The exact behavior depends on the API implementation.
PATCH Requests
PATCH is generally used when only part of a resource needs to be changed.
import requests
changes = {
"price": 1400
}
response = requests.patch(
"https://example.com/api/products/101",
json=changes,
timeout=10
)
print(response.status_code)
PUT vs PATCH
A useful mental model is: PUT commonly represents a full replacement, while PATCH commonly represents a partial modification.
DELETE Requests
DELETE is commonly used to remove a resource.
import requests
response = requests.delete(
"https://example.com/api/products/101",
timeout=10
)
print(response.status_code)
Some APIs return 204 No Content after a
successful deletion.
HTTP Status Codes
Status codes allow your application to determine what happened during an API request.
2xx — Success
- 200 — OK
- 201 — Created
- 204 — No Content
4xx — Client Problems
- 400 — Bad Request
- 401 — Unauthorized
- 403 — Forbidden
- 404 — Not Found
- 429 — Too Many Requests
5xx — Server Problems
- 500 — Internal Server Error
- 502 — Bad Gateway
- 503 — Service Unavailable
Request Headers
Headers provide additional information about a request.
import requests
headers = {
"Accept": "application/json",
"User-Agent": "PyLearn-App"
}
response = requests.get(
"https://example.com/api/products",
headers=headers,
timeout=10
)
print(response.status_code)
APIs may use headers to communicate content formats, authentication credentials and other metadata.
API Authentication
Public APIs may allow anonymous requests, while private APIs usually require authentication.
One common authentication pattern is a bearer token.
import requests
token = "YOUR_API_TOKEN"
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.get(
"https://example.com/api/profile",
headers=headers,
timeout=10
)
response.raise_for_status()
print(response.json())
Security Rule
Never put real API tokens, passwords or private credentials directly into source code that may be published or committed to Git.
A better approach is to read secrets from environment variables or a dedicated secrets-management system.
Pagination
APIs may contain thousands or millions of records. Returning everything in one response would be inefficient.
APIs therefore commonly divide results into pages.
GET /products?page=1
GET /products?page=2
GET /products?page=3
A Python client might request multiple pages:
import requests
all_products = []
for page in range(1, 4):
response = requests.get(
"https://example.com/api/products",
params={"page": page},
timeout=10
)
response.raise_for_status()
products = response.json()
all_products.extend(products)
print("Products:", len(all_products))
Real-World Consideration
Different APIs implement pagination differently. You may encounter page numbers, offsets, cursors or links to the next page.
Filtering & Searching
APIs often provide query parameters that allow clients to request only the data they need.
params = {
"category": "electronics",
"min_price": 500,
"page": 1
}
response = requests.get(
"https://example.com/api/products",
params=params,
timeout=10
)
Search parameters might look like:
GET /products?search=laptop
GET /products?category=electronics
GET /products?sort=price
The exact parameter names are determined by the API.
Handling API Errors
A professional API client should expect failures.
import requests
try:
response = requests.get(
"https://example.com/api/products",
timeout=10
)
response.raise_for_status()
data = response.json()
except requests.exceptions.Timeout:
print("The request timed out.")
except requests.exceptions.HTTPError as error:
print("HTTP error:", error)
except requests.exceptions.ConnectionError:
print("Could not connect to the server.")
except ValueError:
print("The response was not valid JSON.")
except requests.exceptions.RequestException as error:
print("Request failed:", error)
Think Beyond 200 OK
A robust application considers network failures, authentication errors, rate limits, invalid data and temporary server problems.
Building a Reusable API Client
Instead of repeating the same request logic throughout your program, you can create functions or classes that act as an API client.
import requests
def get_products(base_url):
response = requests.get(
f"{base_url}/products",
timeout=10
)
response.raise_for_status()
return response.json()
products = get_products(
"https://example.com/api"
)
for product in products:
print(product["name"])
This separates network communication from the rest of your application logic.
Why This Matters
- Less duplicated code
- Easier testing
- Centralized error handling
- Easier API changes
- Cleaner application architecture
Practical Ecommerce Example
Imagine that an ecommerce application receives product information from an external API.
import requests
def fetch_products():
url = "https://example.com/api/products"
try:
response = requests.get(
url,
params={
"category": "electronics",
"page": 1
},
timeout=10
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as error:
print("API request failed:", error)
return []
products = fetch_products()
for product in products:
name = product.get("name", "Unknown")
price = product.get("price", 0)
print(f"{name}: ${price}")
This example demonstrates several professional concepts together:
- Function abstraction
- Query parameters
- Timeouts
- HTTP error handling
- JSON parsing
- Safe dictionary access
Architecture Connection
An ecommerce platform could use this same pattern to synchronize products, orders, customers, inventory or shipping information with another system.
REST API Best Practices
1. Use Timeouts
Never assume that a remote server will respond immediately.
2. Check Status Codes
Always determine whether the operation succeeded.
3. Handle Exceptions
Network failures are normal possibilities and should be handled.
4. Protect Credentials
Keep API keys and tokens outside public source code.
5. Respect Rate Limits
APIs may limit how many requests a client can make.
6. Read API Documentation
Never guess an API's endpoints, parameters or required fields when documentation is available.
7. Keep API Logic Organized
Put repeated API communication into reusable functions or classes.
Common REST API Mistakes
Mistake 1 — Assuming Every Request Succeeds
Always inspect the response status.
Mistake 2 — Ignoring API Documentation
Every API has its own endpoint structure, parameters and authentication requirements.
Mistake 3 — Hard-Coding Secrets
API credentials should be stored securely.
Mistake 4 — No Timeout
Network requests should have sensible timeout behavior.
Mistake 5 — Assuming JSON Is Always Valid
A server may return an error page, empty response or malformed data.
Mistake 6 — Ignoring Pagination
APIs often return only a portion of a large dataset.
Practice Exercises
Exercise 1 — Retrieve Products
Write a function that sends a GET request to a products endpoint and returns the JSON data.
Exercise 2 — Add Query Parameters
Modify your function so it accepts a category and page number.
Exercise 3 — Handle Errors
Add timeout handling, HTTP error handling and connection error handling.
Exercise 4 — Create a Product
Write a POST request that sends a product as JSON.
Exercise 5 — Pagination
Retrieve three pages of products and combine them into one Python list.
Mini Challenge — Ecommerce REST API Client
Build a small Python API client for an imaginary ecommerce platform.
Your Mission
-
Create a function called
get_products(). - Send a GET request.
-
Add pagination using a
pageparameter. - Set a timeout.
-
Call
raise_for_status(). - Parse the JSON response.
- Print each product's name and price.
- Filter products costing more than 500.
- Handle request failures gracefully.
Starter Code
import requests
def get_products(page=1):
url = "https://example.com/api/products"
try:
response = requests.get(
url,
params={
"page": page
},
timeout=10
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as error:
print("API error:", error)
return []
products = get_products(page=1)
for product in products:
name = product.get("name", "Unknown")
price = product.get("price", 0)
if price > 500:
print(
f"{name} - ${price}"
)
Advanced Extension
Extend your program so that it:
- retrieves multiple pages,
- counts the total products,
- calculates the average price,
- finds the most expensive product,
- stores the results in SQLite.
REST API
↓
Requests
↓
JSON
↓
Python Data
↓
Data Processing
↓
SQLite
↓
Ecommerce Report
Professional Challenge
Try separating your project into an API client function, data-processing functions and database functions. This introduces a cleaner architecture similar to real software projects.
Knowledge Check
1. What does API stand for?
2. What is REST?
3. Which method commonly retrieves a resource?
4. Which method commonly creates a resource?
5. Which format is frequently used by REST APIs?
6. What does status code 404 mean?
7. Why is pagination used?
8. Why should API tokens not be hard-coded?
9. Which status code commonly indicates creation?
10. What is a REST resource?
Lesson Summary
REST APIs provide a structured way for applications to communicate over HTTP.
What You Learned
- APIs allow software systems to communicate.
- REST is an architectural style for designing networked APIs.
- REST APIs organize information around resources.
- HTTP methods describe operations on resources.
- JSON is commonly used to exchange structured data.
- GET retrieves information.
- POST commonly creates resources.
- PUT commonly replaces resources.
- PATCH commonly performs partial updates.
- DELETE commonly removes resources.
- Status codes communicate request results.
- Headers carry additional request information.
- Authentication protects private APIs.
- Pagination handles large datasets.
- Query parameters support filtering and searching.
- Robust clients need timeouts and exception handling.
- API logic can be organized into reusable functions or classes.
You now understand the architecture behind many modern web services. In the next lesson, we will move from consuming APIs to another powerful Python skill: Web Scraping.
Ready to Continue?
You have completed the Python REST APIs lesson.