Chapter 21 of 21
Web Scraping: Beautiful Soup
Current Study Module
High-Performance APIs: FastAPI
Chapter 20 • Modern Backend & Microservices

High-Performance Web APIs with FastAPI & Pydantic

FastAPI is one of the fastest-growing web frameworks in the software industry. Built on top of Starlette (for lightning-fast async networking) and Pydantic(for Rust-accelerated data validation), FastAPI delivers Go and Node.js-tier throughput while providing 100% type safety and zero-effort interactive OpenAPI documentation.

1. The Architectural Shift: WSGI vs ASGI

Legacy Python web frameworks like Django and Flask run on the synchronous WSGI (Web Server Gateway Interface)standard. Under WSGI, each incoming HTTP request occupies an entire operating system thread. If 1,000 requests simultaneously wait for database queries or third-party APIs, the server requires 1,000 blocked threads, leading to heavy memory consumption and context-switching bottlenecks.

FastAPI runs on the modern ASGI (Asynchronous Server Gateway Interface) standard powered byUvicorn. ASGI uses an asynchronous single-threaded event loop (via Libuv). When a request initiates an I/O operation (database read, external API fetch), the event loop pauses that coroutine and immediately processes other pending requests on the same thread:

Metric / FeatureWSGI (Flask / Classic Django)ASGI (FastAPI / Starlette)
Concurrency ModelMulti-threaded / Multi-process blockingSingle/Multi-worker Async Event Loop
WebSockets & SSERequires complex workarounds / external daemonsNative first-class support
I/O Bound Throughput~1,000 - 3,000 requests/sec~20,000 - 50,000+ requests/sec
Data ValidationManual parsing or external marshmallow schemasAutomatic via Pydantic v2 (Rust core)

2. Installing FastAPI & Running Uvicorn

Install FastAPI along with the standard Uvicorn production web server:

pip install "fastapi[standard]"

Create a file named main.py and define your route handlers using standard Python type annotations:

from fastapi import FastAPI, HTTPException, status
from typing import Optional

app = FastAPI(
    title="Inventory Microservice",
    description="Production-grade asynchronous REST API powered by FastAPI & Pydantic",
    version="1.0.0"
)

# 1. Root Health Check Endpoint
@app.get("/", tags=["Health Check"])
async def root():
    return {"status": "healthy", "service": "inventory-api", "version": "1.0.0"}

# 2. Path & Query Parameters with Type Validation
@app.get("/items/{item_id}", tags=["Inventory"])
async def get_item(
    item_id: int,                      # Validated as integer; 422 error if string sent
    include_stock: bool = True,        # Query param e.g. ?include_stock=false
    search_tag: Optional[str] = None   # Optional query param
):
    if item_id > 1000:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Item with ID {item_id} does not exist."
        )
        
    return {
        "item_id": item_id,
        "include_stock": include_stock,
        "search_tag": search_tag,
        "name": f"Product-{item_id}"
    }

Start the server using Uvicorn with hot-reloading enabled for development:

uvicorn main:app --reload --port 8000

3. Request & Response Models with Pydantic v2

FastAPI relies on Pydantic to enforce schema validation on incoming JSON payloads and filter outbound JSON responses. If a client submits invalid JSON (missing required fields, negative prices, wrong datatypes), FastAPI rejects the payload automatically with detailed error metadata before your function body even executes:

from fastapi import FastAPI, status, HTTPException
from pydantic import BaseModel, Field, EmailStr
from typing import List, Optional
from datetime import datetime

# 1. Outbound / Inbound Pydantic Data Models
class ProductCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=100, description="Name of the product")
    sku: str = Field(..., min_length=4, max_length=12, pattern="^[A-Z0-9-]+$")
    price: float = Field(..., gt=0.0, description="Price must be strictly positive")
    tags: List[str] = Field(default_factory=list)
    contact_email: Optional[EmailStr] = None

class ProductResponse(ProductCreate):
    id: int
    created_at: datetime

    class Config:
        from_attributes = True

# In-memory storage mock
fake_db = {}
id_counter = 1

# 2. POST Endpoint with Automatic JSON Deserialization & Response Filtering
@app.post("/products", response_model=ProductResponse, status_code=status.HTTP_201_CREATED, tags=["Products"])
async def create_product(payload: ProductCreate):
    global id_counter
    new_product = {
        **payload.model_dump(),
        "id": id_counter,
        "created_at": datetime.utcnow()
    }
    fake_db[id_counter] = new_product
    id_counter += 1
    
    return new_product

4. The Dependency Injection (DI) Engine

FastAPI has an exceptionally elegant Dependency Injection system using Depends(). It allows you to share database connections, extract JWT authentication tokens, and enforce permission checks across routes without repetitive boilerplate:

from fastapi import Depends, Header, HTTPException, status

# Dependency 1: Mock Header Authentication
async def verify_api_key(x_api_key: str = Header(...)):
    if x_api_key != "secret-production-key-99":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or missing X-API-Key header"
        )
    return {"user": "authorized_service_agent"}

# Dependency 2: Yield Dependency for Resource Management (like DB sessions)
async def get_db_session():
    print("-> Opening DB connection...")
    db_session = {"connection": "active_postgres_pool"}
    try:
        yield db_session
    finally:
        print("<- Closing DB connection cleanly!")

# Secure Route using both dependencies injected automatically!
@app.delete("/products/{product_id}", tags=["Admin"])
async def delete_product(
    product_id: int,
    auth_user: dict = Depends(verify_api_key),
    db: dict = Depends(get_db_session)
):
    if product_id not in fake_db:
        raise HTTPException(status_code=404, detail="Product not found")
        
    del fake_db[product_id]
    return {
        "success": True, 
        "deleted_id": product_id, 
        "authorized_by": auth_user["user"]
    }

5. Automatic Interactive Swagger & OpenAPI Docs

Because FastAPI inspects Python 3.12+ type hints, Pydantic schemas, and docstrings at runtime, it automatically generates two interactive documentation interfaces without writing a single line of YAML:

Swagger UI

http://localhost:8000/docs

Interactive REST playground. Send live GET, POST, and DELETE requests, authenticate with headers, and test JSON responses directly in your browser.

ReDoc

http://localhost:8000/redoc

A clean, publication-ready API specification document formatted with multi-column layouts, code samples, and complete request/response schemas.

🎉

Congratulations! Python Masterclass Completed!

You have completed all 21 chapters of the Python Masterclass—from CPython compilation, memory pointers, and OOP internals, through to asynchronous event loops, data science vectorization, and production REST APIs.

🎉 Python Mastery Complete! Ready for AI & Machine Learning.

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools