Phase 3: Backend & APIs

HTTP status codes, pagination & filtering

Intermediate ~3 min read
Think of it this way A friendly analogy. Read this if the technical version feels dense. Show Hide

Imagine you're at a giant library, a super-duper special one where computers ask for information using an API (Application Programming Interface). When a computer asks for a book, it needs a clear answer, right? That's what HTTP status codes are for. They're like the librarian's secret signals. If the librarian gives a thumbs up and the book, that's like a 200 OK code – everything worked! If they say, 'Sorry, we don't have that one,' that's a 404 Not Found code. If the computer asked for the book with a typo, the librarian might say, 'I don't understand that request,' which is a 400 Bad Request. And if the librarian's computer crashes, that's a 500 Internal Server Error – a problem on their side! These signals instantly tell the asking computer what happened, so it doesn't have to read a long message every time.

Now, imagine the library has thousands of books about animals. You don't want to carry all of them home at once! And the librarian doesn't want to list every single animal book in one go. That's where pagination comes in. Instead of giving you everything, the librarian gives you a small, manageable list – maybe just the first 10 animal books. Then, if you want more, you can ask for the 'next 10.' This way, you only get a few books at a time, making it much easier to look through, and the librarian doesn't get overwhelmed trying to show you everything at once. It's like turning pages in a big book, a few at a time.

But what if you don't just want "animal books"? What if you specifically want "dog books about adventures" or "cat books written by your favorite author"? That's where filtering helps. You tell the librarian exactly what you're looking for, and they'll narrow down their search to find only the books that match your specific requests. Instead of all animal books, they'll only show you the dog adventure books. It's like using different search categories on a website to find exactly what you want, faster.

So, when you build your own amazing computer programs that talk to other programs, using these ideas helps everyone. You can give clear signals about what happened with a request, make sure you're not sending too much information at once, and help users find exactly what they're looking for. This means you can create smooth, helpful computer experiences, just like a well-organized library.

HTTP status codes are like traffic signals for your API, communicating the outcome of a client's request. They're essential for client-side error handling, debugging, and understanding API behavior without digging into the response body every time. For instance, a 200 OK means success, 201 Created indicates a new resource was made, 400 Bad Request signals a client-side error (like invalid input), 404 Not Found means the requested resource doesn't exist, and 500 Internal Server Error points to a problem on the server's side. Always return the most appropriate status code; don't just default to 200 OK for errors.

When dealing with large collections of data, sending everything in a single API response is inefficient and can overwhelm both the server and the client. Pagination solves this by breaking down large datasets into smaller, manageable chunks or "pages." Common approaches include offset-based (e.g., ?offset=10&limit=5 to skip the first 10 items and get the next 5) or cursor-based (e.g., ?after=encoded_id&limit=10 for more performant scrolling through very large, dynamic datasets). Good pagination also includes metadata in the response, such as total item count, current page number, and total pages, to help clients build navigation.

Filtering allows clients to retrieve only the specific data they need, rather than the entire collection. This is typically implemented using query parameters in the URL. For example, GET /products?category=electronics would return only products in the electronics category, or GET /users?status=active&role=admin would fetch active administrators. Thoughtful filtering improves performance by reducing the amount of data transferred and processed, and enhances user experience by providing relevant results faster. Combine filtering with pagination to create powerful and flexible data retrieval endpoints.

Key Takeaways

  • Always use appropriate HTTP status codes for clear API communication and robust error handling.
  • Implement pagination for large collections to improve performance and client-side usability.
  • Offer filtering options via query parameters to allow clients to request specific subsets of data.
  • Combine pagination and filtering for powerful and efficient data retrieval in your APIs.

Code Example

python
from flask import Flask, request, jsonify

app = Flask(__name__)

products_db = [
    {"id": 1, "name": "Laptop", "category": "electronics", "in_stock": True},
    {"id": 2, "name": "Keyboard", "category": "electronics", "in_stock": True},
    {"id": 3, "name": "Chair", "category": "furniture", "in_stock": False},
]

@app.route('/products', methods=['GET'])
def get_products():
    filtered = products_db

    # Filtering by category and stock status
    category = request.args.get('category')
    in_stock_str = request.args.get('in_stock')
    if category: filtered = [p for p in filtered if p['category'] == category]
    if in_stock_str is not None: 
        is_in_stock = in_stock_str.lower() == 'true'
        filtered = [p for p in filtered if p['in_stock'] == is_in_stock]

    # Pagination
    page = int(request.args.get('page', 1))
    limit = int(request.args.get('limit', 10))
    start = (page - 1) * limit
    end = start + limit
    paginated = filtered[start:end]

    return jsonify({
        "products": paginated,
        "total": len(filtered),
        "page": page, "limit": limit
    }), 200

How this code works

This Flask application serves as an example of a REST API endpoint that fetches product data with capabilities for filtering and pagination. The products_db list simulates a database of items. The /products endpoint's get_products function first initializes a list with all products. It then processes category and in_stock query parameters from request.args.get. If category is present, the product list is filtered to match. For in_stock, the string value from the request is converted to a boolean to filter items based on their availability. This order-of-operations ensures filtering happens before pagination.

After filtering, the code handles pagination. It retrieves page and limit parameters from the request, using int(request.args.get('page', 1)) and int(request.args.get('limit', 10)) to set sensible default values if these aren't provided by the API consumer. This subtle default value handling ensures the API always returns a first page of 10 items even without explicit pagination parameters. It calculates start and end indices to slice the filtered list, returning only the specific paginated subset. The function then uses jsonify to send back the paginated products, the total count of all filtered products, and the current page and limit values, all with an HTTP 200 status code indicating success.