Chapter 17 Exercises: Backend Development and REST APIs

These exercises are organized into five tiers of increasing complexity, following Bloom's taxonomy. Work through them sequentially within each tier, as later exercises often build on earlier ones.


Tier 1: Remember and Understand (Exercises 1-6)

These exercises test your recall of backend concepts and your ability to explain them.

Exercise 1: HTTP Method Matching

Match each HTTP method to its primary CRUD operation and indicate whether it is idempotent.

HTTP Method CRUD Operation Idempotent?
GET ? ?
POST ? ?
PUT ? ?
PATCH ? ?
DELETE ? ?

Exercise 2: Status Code Identification

For each scenario, identify the most appropriate HTTP status code:

  1. A user successfully creates a new account
  2. A user requests a profile that does not exist
  3. A user sends a request without a required authentication token
  4. A user tries to delete another user's data and lacks permission
  5. The server encounters an unexpected database connection failure
  6. A user sends a JSON body with an invalid email format
  7. A user tries to create a username that already exists
  8. A user successfully deletes a resource and no response body is needed
  9. A user has exceeded the API rate limit
  10. A GET request for a list of items succeeds

Exercise 3: REST URL Evaluation

Evaluate each URL and explain whether it follows REST conventions. If it does not, suggest an improvement.

  1. GET /api/getUsers
  2. POST /api/users/create
  3. GET /api/v1/users/42/orders
  4. DELETE /api/User/42
  5. GET /api/v1/products?category=electronics&sort=price&order=asc
  6. PUT /api/v1/orders/100/items/5
  7. POST /api/deleteUser/42
  8. GET /api/v1/user-profiles/42

Exercise 4: Flask vs. FastAPI Comparison

Create a comparison table listing at least five differences between Flask and FastAPI across these categories: validation approach, async support, documentation generation, type hint usage, and learning curve. For each difference, explain which framework you would recommend and why.

Exercise 5: Request-Response Trace

Trace the complete request-response cycle for this scenario: a user submits a login form on a web page. Describe each step from the browser sending the request to receiving and processing the response. Include: HTTP method, URL, headers, request body, server processing steps, response status code, response headers, and response body.

Exercise 6: Pydantic Model Reading

Given the following Pydantic model, answer the questions below:

class ProductCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    price: float = Field(..., gt=0, le=999999.99)
    category: str = Field(..., pattern=r"^[a-z_]+$")
    quantity: int = Field(default=0, ge=0)
    description: Optional[str] = Field(None, max_length=500)
  1. Which fields are required?
  2. What is the default value for quantity?
  3. Would {"name": "", "price": 10.0, "category": "books"} pass validation? Why or why not?
  4. Would {"name": "Widget", "price": -5, "category": "tools"} pass validation? Why or why not?
  5. Would {"name": "Widget", "price": 10.0, "category": "Home Goods"} pass validation? Why or why not?
  6. Is the description field required? What is its constraint?

Tier 2: Apply (Exercises 7-12)

These exercises require you to use AI to generate and modify backend code.

Exercise 7: Flask CRUD API

Use an AI assistant to generate a Flask API for managing a collection of recipes. Each recipe should have: id, title, ingredients (list of strings), instructions (text), prep_time_minutes (integer), and cuisine (string).

Requirements: - All five CRUD endpoints (list, get, create, update, delete) - In-memory storage with a list of dictionaries - Proper HTTP status codes for each operation - Input validation that checks for required fields and appropriate types - Error handling for not-found and invalid input scenarios

Your task: Write the prompt, generate the code, then manually verify that all five endpoints return correct status codes.

Exercise 8: FastAPI with Pydantic Models

Use an AI assistant to create a FastAPI application for managing a contact list. Each contact has: id, first_name, last_name, email, phone (optional), company (optional), and created_at.

Requirements: - Separate Pydantic models for creation (ContactCreate) and response (ContactResponse) - Email validation using Pydantic's EmailStr - Phone number validation with a regex pattern - List endpoint with filtering by company and pagination (page, per_page) - Proper OpenAPI documentation with tags and descriptions

Your task: Write the prompt, generate the code, and verify the auto-generated docs at /docs by running the application.

Exercise 9: JWT Authentication

Use an AI assistant to add JWT authentication to a FastAPI application. Start with this base:

from fastapi import FastAPI

app = FastAPI()

# In-memory user store
users_db = {}

Requirements: - Registration endpoint (POST /api/auth/register) with username, email, password - Login endpoint (POST /api/auth/login) that returns access and refresh tokens - Token refresh endpoint (POST /api/auth/refresh) - Protected endpoint (GET /api/me) that returns the current user's profile - Password hashing with bcrypt - Token expiration (access: 15 minutes, refresh: 7 days)

Your task: Write a series of prompts to build this incrementally. First the registration, then login, then the protected endpoint.

Exercise 10: Error Handling Middleware

Use an AI assistant to create a FastAPI application with comprehensive error handling.

Requirements: - Custom exception classes: NotFoundError, ValidationError, AuthenticationError, PermissionError - A global exception handler that converts all custom exceptions to JSON responses - A catch-all handler for unexpected exceptions that logs the error and returns a generic 500 response - Different error detail levels for debug mode vs. production mode - Request ID in every error response

Your task: Write the prompt, generate the code, then test it by deliberately triggering each error type.

Exercise 11: Flask Blueprints

Refactor a monolithic Flask application into blueprints. Start with this single-file application that has endpoints for users, products, and orders (at least two endpoints each). Use AI to restructure it into:

app/
├── __init__.py      # Application factory
├── blueprints/
│   ├── users.py     # User routes
│   ├── products.py  # Product routes
│   └── orders.py    # Order routes
└── run.py           # Entry point

Your task: Write prompts to generate both the monolithic version and the refactored version. Compare the two and note what the AI did well and what it missed.

Exercise 12: API Rate Limiting

Use an AI assistant to implement rate limiting for a FastAPI application.

Requirements: - Different rate limits for different endpoint groups (auth: 5/minute, read: 60/minute, write: 20/minute) - Rate limit information in response headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) - Configurable rate limits via environment variables - Proper 429 response with Retry-After header

Your task: Write the prompt, generate the code, and write a simple script that tests the rate limiting by making rapid requests.


Tier 3: Analyze (Exercises 13-18)

These exercises require you to evaluate and analyze backend code critically.

Exercise 13: Security Audit

Review the following AI-generated authentication code and identify all security vulnerabilities:

@app.post("/login")
async def login(username: str, password: str):
    user = db.query(f"SELECT * FROM users WHERE username='{username}'")
    if user and user.password == password:
        token = base64.b64encode(f"{username}:{time.time()}".encode()).decode()
        return {"token": token}
    return {"error": "Invalid credentials"}, 401

@app.get("/admin")
async def admin_panel(token: str = Header(None)):
    decoded = base64.b64decode(token).decode()
    username = decoded.split(":")[0]
    return {"message": f"Welcome admin {username}"}

List every vulnerability you can find and explain how to fix each one.

Exercise 14: Performance Analysis

Analyze this FastAPI endpoint for performance issues:

@app.get("/api/reports/summary")
async def get_report_summary():
    users = await db.fetch_all("SELECT * FROM users")
    result = []
    for user in users:
        orders = await db.fetch_all(
            f"SELECT * FROM orders WHERE user_id = {user['id']}"
        )
        total = 0
        for order in orders:
            items = await db.fetch_all(
                f"SELECT * FROM order_items WHERE order_id = {order['id']}"
            )
            for item in items:
                product = await db.fetch_one(
                    f"SELECT price FROM products WHERE id = {item['product_id']}"
                )
                total += product['price'] * item['quantity']
        result.append({"user": user['name'], "total_spent": total})
    return result

Identify the performance problems (there are at least four), explain why each is a problem, and describe how to fix them. Then write a prompt asking AI to refactor this endpoint.

Exercise 15: API Design Review

A junior developer designed this API for a blog platform. Review the URL structure and identify all design problems:

POST   /api/blogs/newBlog
GET    /api/blogs/getAllBlogs
GET    /api/blog/getBlogById/42
PUT    /api/blogs/updateBlog
DELETE /api/blogs/deleteBlog/42
POST   /api/blogs/42/addComment
GET    /api/comments/getByBlog/42
POST   /api/users/loginUser
GET    /api/Users/42
PUT    /api/blogs/42/like

Redesign the entire API following REST best practices. Explain each change.

Exercise 16: Framework Selection

For each of the following project scenarios, analyze which framework (Flask or FastAPI) would be the better choice, and explain your reasoning:

  1. A simple webhook receiver that processes GitHub events
  2. A real-time chat API serving thousands of concurrent WebSocket connections
  3. Adding an API to an existing Flask-based web application
  4. A greenfield microservice for a financial trading platform
  5. A quick prototype API for a hackathon project
  6. An API that will be consumed by a mobile app team who needs comprehensive documentation

Exercise 17: Middleware Order Analysis

Given this FastAPI application with multiple middleware layers, trace the execution order for a request to GET /api/tasks/1 that is authenticated and within rate limits:

@app.middleware("http")
async def timing_middleware(request, call_next):
    print("TIMING: start")
    response = await call_next(request)
    print("TIMING: end")
    return response

@app.middleware("http")
async def auth_middleware(request, call_next):
    print("AUTH: start")
    response = await call_next(request)
    print("AUTH: end")
    return response

@app.middleware("http")
async def logging_middleware(request, call_next):
    print("LOGGING: start")
    response = await call_next(request)
    print("LOGGING: end")
    return response

What is the order of the print statements? Explain why. What happens if auth_middleware raises an HTTPException instead of calling call_next?

Exercise 18: Error Response Comparison

Compare these three error response formats and analyze the trade-offs of each:

Format A:

{"error": "Not found"}

Format B:

{
    "error": {
        "code": "RESOURCE_NOT_FOUND",
        "message": "Task with ID 42 not found",
        "details": {"resource_type": "task", "resource_id": 42}
    }
}

Format C:

{
    "errors": [
        {
            "status": "404",
            "code": "RESOURCE_NOT_FOUND",
            "title": "Resource Not Found",
            "detail": "Task with ID 42 not found",
            "source": {"pointer": "/api/tasks/42"},
            "meta": {"timestamp": "2025-03-15T10:30:00Z"}
        }
    ]
}

For each format, discuss: ease of implementation, usefulness for client developers, support for multiple errors, extensibility, and compliance with any standards.


Tier 4: Evaluate and Create (Exercises 19-24)

These exercises require you to design and build more complex backend systems.

Exercise 19: API Versioning Strategy

Design and implement an API versioning strategy for a FastAPI application that supports both v1 and v2 of a users API. V1 returns {"name": "full name"} and v2 returns {"first_name": "...", "last_name": "..."}.

Requirements: - Both URL-based versioning (/api/v1/users, /api/v2/users) and header-based versioning (Accept: application/vnd.myapi.v2+json) should be supported - Shared business logic between versions - Clear separation of version-specific schemas - Deprecation warnings for v1 endpoints

Use AI to implement this, then evaluate the generated architecture.

Exercise 20: Pagination System

Design and implement a comprehensive pagination system for a FastAPI application.

Requirements: - Support for both offset-based and cursor-based pagination - Consistent pagination metadata in responses (total count, page size, next/previous links) - Proper handling of edge cases (page beyond total, negative offset, invalid cursor) - Query parameter validation - Support for sorting by multiple fields

Generate Pydantic models for pagination parameters and responses. Implement both pagination strategies and write prompts that produce correct implementations.

Exercise 21: Webhook System

Design and implement a webhook notification system as a FastAPI sub-application.

Requirements: - CRUD for webhook subscriptions (URL, events to subscribe to, secret) - Webhook delivery with retry logic (3 retries with exponential backoff) - Signature verification using HMAC-SHA256 - Delivery status tracking (pending, delivered, failed) - A test endpoint that triggers a fake event

Use AI to generate the complete system, then review the generated code for reliability and security issues.

Exercise 22: API Gateway Pattern

Create a simple API gateway using FastAPI that routes requests to multiple backend services.

Requirements: - Route /api/users/ to a user service - Route /api/products/ to a product service - Route /api/orders/* to an order service - Central authentication that validates tokens before proxying - Request/response logging - Circuit breaker pattern for handling service failures

Use AI to implement the gateway and at least one mock backend service.

Exercise 23: GraphQL vs. REST Comparison

Implement the same functionality as both a REST API and a GraphQL API using FastAPI:

Functionality: A library system with books, authors, and reviews. Users can query books with their authors and reviews, filter by genre, and create new reviews.

Task: - Use AI to generate the REST version with multiple endpoints - Use AI to generate the GraphQL version using Strawberry or Ariadne - Compare: number of endpoints, request count for a complex page, response size, ease of evolution - Write a 500-word analysis of when each approach is preferable

Exercise 24: Full CRUD with Testing

Build a complete FastAPI application for managing a library with books, authors, and categories.

Requirements: - Full CRUD for all three resources - Relationships: books have one author and one or more categories - Search endpoint that searches across titles, authors, and descriptions - JWT authentication with admin and reader roles - Comprehensive test suite with at least 80% code coverage - OpenAPI documentation with examples for every endpoint

Use AI to generate all code, then use AI to review the generated code for issues. Document every issue found and the prompt used to fix it.


Tier 5: Synthesis and Production (Exercises 25-30)

These exercises involve building production-grade systems.

Exercise 25: Microservice Communication

Design and implement two FastAPI microservices that communicate with each other:

Service A: Order Service - Create, read, update orders - Validates product availability by calling Service B - Publishes order events

Service B: Inventory Service - Manages product inventory - Reserves and releases inventory - Responds to availability checks from Service A

Implement both services with proper error handling for network failures between them. Use AI to generate both services and a docker-compose file to run them together.

Exercise 26: Real-Time API Features

Extend a FastAPI application with real-time capabilities:

Requirements: - WebSocket endpoint for live task updates - Server-Sent Events (SSE) endpoint for activity feeds - Connection management (track connected clients, handle disconnects) - Broadcast updates when tasks are created, updated, or deleted - Authentication for WebSocket connections

Use AI to implement the real-time features and a simple HTML client for testing.

Exercise 27: API Performance Optimization

Start with a deliberately unoptimized FastAPI application (use AI to generate one with common performance anti-patterns). Then use AI to systematically optimize it:

  1. Add response caching with configurable TTL
  2. Implement database query optimization (N+1 query elimination, proper indexing)
  3. Add connection pooling
  4. Implement background task processing for slow operations
  5. Add response compression

For each optimization, measure the before and after performance using a load testing tool.

Exercise 28: Multi-Tenant API

Design and implement a multi-tenant SaaS API using FastAPI:

Requirements: - Tenant isolation at the data layer - Tenant identification via subdomain or header - Tenant-specific rate limiting - Admin endpoints for managing tenants - Tenant-scoped authentication and authorization

Use AI to implement the multi-tenant architecture and write a detailed analysis of the trade-offs between database-per-tenant and schema-per-tenant approaches.

Exercise 29: API Migration Tool

Build a tool using AI that helps migrate a Flask API to FastAPI:

Requirements: - Parse Flask route definitions and generate equivalent FastAPI routes - Convert manual validation to Pydantic models - Convert Flask-JWT-Extended auth to FastAPI's OAuth2 + python-jose - Generate a migration report listing all changes - Handle edge cases (blueprints, custom decorators, extensions)

Test the tool on the Flask API from Exercise 7 and document the accuracy of the migration.

Exercise 30: Production Deployment Pipeline

Create a complete deployment pipeline for a FastAPI application:

Requirements: - Dockerfile with multi-stage build - docker-compose.yml with the API, PostgreSQL, and Redis - Health check endpoint that validates database and cache connectivity - Structured JSON logging with correlation IDs - Prometheus metrics endpoint (/metrics) - Configuration via environment variables with Pydantic settings - GitHub Actions workflow for CI/CD (lint, test, build, deploy) - Load testing configuration using locust or similar tool

Use AI to generate each component, then assemble and test the complete pipeline.