Logo OnlineCBT
PYTHON Tutorial
PYTHON · LESSON 58

REST APIs with FastAPI

Create validated documented APIs with modern type hints.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive
Updated: 26 Jul 2026

Lesson 58: REST APIs with FastAPI

1. Introduction to Next-Generation Asynchronous Web Engineering

In Lesson 57, we explored synchronous web application development using Flask and WSGI servers. While Flask remains popular for traditional web applications, high-concurrency cloud environments—handling real-time microservices, streaming WebSocket connections, and high-throughput mobile app backends—demand single-process performance matching Node.js and Go.

To achieve this level of performance in Python, web architecture evolved from synchronous WSGI to ASGI (Asynchronous Server Gateway Interface). Built on top of ASGI, Python's asyncio Event Loop, and modern type hint annotations (PEP 484), FastAPI has emerged as the modern enterprise standard for building high-speed RESTful Web APIs.

FastAPI combines extreme execution speed with automatic data validation, automatic serialization, structured error handling, and automated interactive OpenAPI (Swagger UI) documentation without requiring manual documentation authoring.

In this lesson, we will master FastAPI and the Uvicorn ASGI server engine, construct asynchronous path operation functions (`async def`), define strict request schemas using Pydantic (`BaseModel`), leverage Dependency Injection (`Depends()`), enforce error handling via `HTTPException`, inspect auto-generated Swagger documentation (`/docs`), and route incoming API payloads cleanly using Structural Pattern Matching (`match-case`).


2. ASGI Architecture: WSGI vs ASGI Comparison

Understanding why FastAPI outperforms traditional Python frameworks requires examining the transition from WSGI to ASGI:

  • Gateway Interface Protocol
  • WSGI (Web Server Gateway Interface)
  • ASGI (Asynchronous Server Gateway Interface)
  • Execution Paradigm
  • Synchronous Blocking (Thread per Request)
  • Asynchronous Non-Blocking (`async`/`await` Event Loop)
  • Server Engine Driver
  • Gunicorn, uWSGI
  • Uvicorn, Hypercorn
  • Throughput Capacity
  • Moderate (~1,000 req/sec per process)
  • Extreme (~10,000+ req/sec matching Node/Go)
  • Real-time Protocol Support
  • HTTP/1.1 strictly
  • HTTP/1.1, HTTP/2, WebSockets, Server-Sent Events (SSE)
Architectural Dimension Traditional WSGI (Flask / Django) Modern ASGI (FastAPI / Starlette)

3. Getting Started with FastAPI & Uvicorn

FastAPI relies on two primary external dependencies: pydantic for data validation and uvicorn for ASGI web server handling.

# Installing FastAPI and Uvicorn server dependencies:
pip install fastapi uvicorn pydantic

# Command-Line invocation for running a production FastAPI app:
uvicorn main_app:app --host 0.0.0.0 --port 8000 --reload
    

1. Automatic OpenAPI / Swagger UI Documentation (`/docs`)

When you run a FastAPI application, FastAPI inspects Python type hints on your routes and automatically publishes interactive OpenAPI web documentation accessible directly at http://127.0.0.1:8000/docs (Swagger UI) and http://127.0.0.1:8000/redoc!

FASTAPI_BASIC_ROUTING.PY
from fastapi import FastAPI, HTTPException, status
from fastapi.testclient import TestClient

# 1. Instantiating core FastAPI Application with metadata
app = FastAPI(
    title="Enterprise Gateway API",
    description="High-throughput RESTful Microservice Engine",
    version="1.0.0"
)

# 2. Static Root Asynchronous Path Handler
@app.get("/", status_code=status.HTTP_200_OK)
async def api_health_check():
    """Asynchronous Root Endpoint returning API status metadata."""
    return {
        "status": "HEALTHY",
        "protocol": "ASGI",
        "engine": "FastAPI + Uvicorn"
    }

# 3. Dynamic Path Parameter Handler with Explicit Type Annotations
@app.get("/api/v1/users/{user_id}", status_code=status.HTTP_200_OK)
async def fetch_user_by_id(user_id: int):
    """
    FastAPI enforces int type constraints on path parameters automatically.
    Passing a string like '/users/abc' triggers HTTP 422 Unprocessable Entity!
    """
    if user_id <= 0:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="User ID must be a positive integer!"
        )
    
    if user_id == 1001:
        return {"user_id": user_id, "username": "alice_dev", "role": "ADMIN"}

    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail=f"User #{user_id} does not exist in registry."
    )

# 4. Testing Endpoints programmatically using FastAPI's built-in TestClient
client = TestClient(app)

print("=== 1. Testing Root GET Endpoint ===")
res1 = client.get("/")
print("Status Code :", res1.status_code)
print("JSON Payload:", res1.json())

print("\n=== 2. Testing Valid User Path Endpoint ===")
res2 = client.get("/api/v1/users/1001")
print("Status Code :", res2.status_code)
print("JSON Payload:", res2.json())

print("\n=== 3. Testing Automatic Type Validation (Passing invalid string ID) ===")
res3 = client.get("/api/v1/users/invalid_id_str")
print("Status Code :", res3.status_code)  # Automatically 422!
print("Error Detail:", res3.json()["detail"][0]["msg"])
OUTPUT
=== 1. Testing Root GET Endpoint ===
Status Code : 200
JSON Payload: {'engine': 'FastAPI + Uvicorn', 'protocol': 'ASGI', 'status': 'HEALTHY'}

=== 2. Testing Valid User Path Endpoint ===
Status Code : 200
JSON Payload: {'role': 'ADMIN', 'user_id': 1001, 'username': 'alice_dev'}

=== 3. Testing Automatic Type Validation (Passing invalid string ID) ===
Status Code : 422
Error Detail: Input should be a valid integer, unable to parse string as an integer

4. Schema Validation & Serialization via Pydantic

In traditional web frameworks, developers must write manual validation code checking if incoming POST JSON dictionaries contain required keys, correct string formats, or numerical ranges.

FastAPI eliminates validation boilerplate by integrating Pydantic. Developers define request body schemas as classes inheriting from `pydantic.BaseModel`. FastAPI parses incoming HTTP JSON payloads, casts data types, validates constraints, and injects strongly-typed model instances directly into route handlers!

1. Defining Pydantic Data Schemas (`BaseModel` and `Field`)

PYDANTIC_SCHEMA_VALIDATION.PY
from fastapi import FastAPI, status
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field, EmailStr
from typing import Literal

# 1. Defining Pydantic Request Body Data Model Schema
class CreateAccountRequest(BaseModel):
    account_id: str = Field(..., min_length=4, max_length=12, description="Unique account identifier")
    email: str = Field(..., description="Valid owner contact email")
    initial_deposit: float = Field(..., gt=0.0, description="Deposit must be strictly greater than 0")
    tier: Literal["STANDARD", "PREMIUM", "VIP"] = "STANDARD"

# 2. Defining Pydantic Response Model Schema
class AccountResponse(BaseModel):
    account_id: str
    owner_email: str
    active_balance: float
    tier: str
    status: str = "ACTIVE"

app = FastAPI()

@app.post(
    "/api/v1/accounts",
    response_model=AccountResponse,  # Automated Response Filtering & Serialization!
    status_code=status.HTTP_201_CREATED
)
async def create_new_account(payload: CreateAccountRequest):
    """
    Receives validated Pydantic model 'payload'.
    FastAPI guarantees all attributes comply with type & Field bounds!
    """
    # Processing business logic using model attributes
    return AccountResponse(
        account_id=payload.account_id,
        owner_email=payload.email,
        active_balance=payload.initial_deposit,
        tier=payload.tier
    )

client = TestClient(app)

print("=== 1. Submitting Valid Pydantic Request Payload ===")
valid_payload = {
    "account_id": "ACC_9901",
    "email": "alice@enterprise.corp",
    "initial_deposit": 1500.00,
    "tier": "PREMIUM"
}
res_ok = client.post("/api/v1/accounts", json=valid_payload)
print("Status Code :", res_ok.status_code)
print("JSON Output :", res_ok.json())

print("\n=== 2. Submitting Invalid Payload (Negative Deposit violating Field(gt=0)) ===")
invalid_payload = {
    "account_id": "ACC_9901",
    "email": "alice@enterprise.corp",
    "initial_deposit": -500.00,  # Invalid!
    "tier": "PREMIUM"
}
res_fail = client.post("/api/v1/accounts", json=invalid_payload)
print("Status Code :", res_fail.status_code)  # Returns 422 Automatically!
print("Validation Error Field:", res_fail.json()["detail"][0]["loc"])
OUTPUT
=== 1. Submitting Valid Pydantic Request Payload ===
Status Code : 201
JSON Output : {'account_id': 'ACC_9901', 'active_balance': 1500.0, 'owner_email': 'alice@enterprise.corp', 'status': 'ACTIVE', 'tier': 'PREMIUM'}

=== 2. Submitting Invalid Payload (Negative Deposit violating Field(gt=0)) ===
Status Code : 422
Validation Error Field: ['body', 'initial_deposit']

5. Dependency Injection System (`Depends()`)

Enterprise API architectures require injecting shared reusable dependencies—such as database connections, security authentication checks, or rate limiters—into route functions.

FastAPI features a powerful Dependency Injection system via `Depends()`.

How Dependency Injection Operates in FastAPI: When a route parameter specifies dep: Type = Depends(dependency_func), FastAPI executes dependency_func first automatically, resolves its returned value, and passes the result cleanly into the route function parameter!
FASTAPI_DEPENDENCY_INJECTION_DEMO.PY
from fastapi import FastAPI, Depends, Header, HTTPException, status
from fastapi.testclient import TestClient

app = FastAPI()

# 1. Dependency Function verifying Security API Header Token
async def verify_bearer_token(authorization: str = Header(...)) -> str:
    """Dependency enforcing Bearer Token authorization header presence."""
    if not authorization.startswith("Bearer ") or len(authorization) < 15:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Missing or malformed Bearer Token authentication header!"
        )
    token_str = authorization.split(" ")[1]
    return f"AUTHENTICATED_USER_FROM_TOKEN_{token_str[-4:]}"

# 2. Route Path Function Injecting Header Token Dependency
@app.get("/api/v1/vault/secrets")
async def read_vault_secrets(user_context: str = Depends(verify_bearer_token)):
    """Protected endpoint accessible ONLY if verify_bearer_token passes!"""
    return {
        "status": "ACCESS_GRANTED",
        "authenticated_user": user_context,
        "secret_payload": "CONFIDENTIAL_ENTERPRISE_DATA"
    }

client = TestClient(app)

print("=== 1. Accessing Protected Route WITH Valid Authorization Header ===")
res_auth = client.get(
    "/api/v1/vault/secrets",
    headers={"Authorization": "Bearer ENTERPRISE_SECRET_TOKEN_99"}
)
print("Status Code :", res_auth.status_code)
print("JSON Output :", res_auth.json())

print("\n=== 2. Accessing Protected Route WITHOUT Header (Denied) ===")
res_no_auth = client.get("/api/v1/vault/secrets")
print("Status Code :", res_no_auth.status_code)
print("JSON Output :", res_no_auth.json())
OUTPUT
=== 1. Accessing Protected Route WITH Valid Authorization Header ===
Status Code : 200
JSON Output : {'authenticated_user': 'AUTHENTICATED_USER_FROM_TOKEN_t_99', 'secret_payload': 'CONFIDENTIAL_ENTERPRISE_DATA', 'status': 'ACCESS_GRANTED'}

=== 2. Accessing Protected Route WITHOUT Header (Denied) ===
Status Code : 422
JSON Output : {'detail': [{'type': 'missing', 'loc': ['header', 'authorization'], 'msg': 'Field required', 'input': None}]}

6. Combining FastAPI Models with `match-case` Pattern Matching

Building scalable event-driven REST API dispatchers involves accepting validated Pydantic model payloads and evaluating model structures using Python 3.10+ `match-case` Structural Pattern Matching.

MATCH_CASE_FASTAPI_DISPATCHER.PY
from pydantic import BaseModel

class WebhookEventPayload(BaseModel):
    event_type: str
    source_service: str
    metadata: dict

def dispatch_webhook_event_payload(event: WebhookEventPayload) -> str:
    """
    Routes validated Pydantic model objects using Structural Pattern Matching.
    Demonstrates evaluating Pydantic model attributes dynamically.
    """
    match event:
        case WebhookEventPayload(event_type="PAYMENT_RECEIVED", source_service=src, metadata={"amount": float(amt)}) if amt >= 10000.0:
            return f"MATCH_HIGH_VALUE_PAYMENT: Processing VIP transaction ${amt:,.2f} from '{src}'."

        case WebhookEventPayload(event_type="PAYMENT_RECEIVED", source_service=src, metadata={"amount": float(amt)}):
            return f"MATCH_STANDARD_PAYMENT: Processing standard payment ${amt:,.2f} from '{src}'."

        case WebhookEventPayload(event_type="SECURITY_ALERT", metadata={"level": "CRITICAL", "message": str(msg)}):
            return f"MATCH_SECURITY_EMERGENCY: Urgent security alert -> '{msg}'!"

        case WebhookEventPayload(event_type=evt_type):
            return f"MATCH_GENERIC_EVENT: Captured event type '{evt_type}' from '{event.source_service}'."

        case _:
            return "UNHANDLED_WEBHOOK_PAYLOAD"

# Testing Dispatcher with Instantiated Pydantic Models
print("=== Pattern Matched FastAPI Webhook Event Outputs ===")
p1 = WebhookEventPayload(
    event_type="PAYMENT_RECEIVED",
    source_service="StripeGateway",
    metadata={"amount": 25000.00}
)
p2 = WebhookEventPayload(
    event_type="SECURITY_ALERT",
    source_service="AuthGuard",
    metadata={"level": "CRITICAL", "message": "Multiple failed SSH root logins"}
)

print(dispatch_webhook_event_payload(p1))
print(dispatch_webhook_event_payload(p2))
OUTPUT
=== Pattern Matched FastAPI Webhook Event Outputs ===
MATCH_HIGH_VALUE_PAYMENT: Processing VIP transaction $25,000.00 from 'StripeGateway'.
MATCH_SECURITY_EMERGENCY: Urgent security alert -> 'Multiple failed SSH root logins'!

7. Frequently Asked Interview Questions with Answers

Q1: What is the primary difference between WSGI and ASGI web server interfaces?
Answer: WSGI (e.g., Flask/Gunicorn) handles requests synchronously in a blocking thread-per-request model. ASGI (e.g., FastAPI/Uvicorn) supports asynchronous, non-blocking I/O execution via Python's asyncio Event Loop, handling thousands of concurrent HTTP connections, WebSockets, and background tasks within a single process.
Q2: How does FastAPI use Pydantic for request validation and serialization?
Answer: FastAPI uses classes inheriting from Pydantic's BaseModel as type annotations in route handlers. Incoming JSON payloads are parsed and validated against model definitions automatically. If validation passes, FastAPI injects the strongly-typed Pydantic object into the route; if validation fails, it returns an automatic 422 Unprocessable Entity JSON error response.
Q3: How does FastAPI generate interactive Swagger UI documentation automatically?
Answer: FastAPI inspects route paths, HTTP verbs, Pydantic schemas, and type annotations at application startup, generating a standardized OpenAPI JSON specification automatically. The built-in Swagger UI engine renders this schema interactively at the /docs path endpoint.
Q4: What is `HTTPException`, and how do you raise custom HTTP errors in FastAPI?
Answer: HTTPException is FastAPI's standard exception class for returning HTTP error responses. Raising raise HTTPException(status_code=404, detail="Resource not found") halts execution and returns a structured JSON error response to the client with the specified status code and message.
Q5: How does Dependency Injection work in FastAPI using `Depends()`?
Answer: The Depends() function specifies reusable callable dependencies (such as database sessions, security tokens, or pagination parameters) as route function arguments. FastAPI executes specified dependency functions automatically before executing the main route handler, passing returned dependency outputs directly into function parameters.

8. Homework & Practical Assignments

Task 1: Asynchronous Pydantic Book Store REST API

Create a script named fastapi_books_task.py inside your lesson_58 folder:

  • Define a Pydantic model BookSchema(title: str, author: str, price: float = Field(gt=0), pages: int = Field(gt=0)).
  • Create a FastAPI app with routes:
    • GET /api/v1/books → Returns list of available books.
    • POST /api/v1/books → Accepts BookSchema body payload and returns created object with status 201.
  • Test both routes using FastAPI's TestClient and print JSON outputs using f-strings.

Task 2: Pattern-Matched Webhook Event Router

Create a script named fastapi_dispatcher_task.py:

  • Define a Pydantic model APIEventModel(service: str, action: str, code: int).
  • Build function process_api_event(event: APIEventModel) -> str.
  • Write a match-case dispatcher:
    • case APIEventModel(action="LOGIN", code=200) → Return "AUTH_SUCCESS".
    • case APIEventModel(action="LOGIN", code=401 | 403) → Return "AUTH_FAILURE_ALERT".
    • case APIEventModel(service="DATABASE", code=500) → Return "DB_CRASH_EMERGENCY".
    • case _ → Return "GENERIC_EVENT_LOGGED".
  • Instantiate 4 model instances, pass through dispatcher, and print output result strings.

Task 3: Master Review Capstone Project — Production Enterprise Asynchronous REST API Gateway OS (`fastapi_gateway_os.py`)

Create a script named fastapi_gateway_os.py inside your lesson_58 folder. This assignment tests and integrates **ALL concepts learned across Lessons 1 through 58**.

Project Architectural Requirements Specification:

  1. FastAPI & REST API Architecture (Lesson 58):
    • Construct an asynchronous FastAPI application with Pydantic request/response schemas (`BaseModel`, `Field`), dynamic path converters, `HTTPException` handling, and Dependency Injection (`Depends()`).
    • Verify endpoints using FastAPI's TestClient.
  2. Flask & Web Development Integration (Lesson 57):
    • Incorporate route parameter patterns and HTTP verb mapping protocols.
  3. RPA & Office Automation Integration (Lesson 56):
    • Generate Excel reports via openpyxl and export email payload alerts using email.message.EmailMessage when specific FastAPI routes are invoked.
  4. Web Scraping Integration (Lesson 55):
    • Extract HTML elements using BeautifulSoup4 (`bs4`) to serve data endpoints inside FastAPI routes.
  5. HTTP APIs & requests Integration (Lesson 54):
    • Integrate background HTTP external health checks via requests.Session().
  6. SQLite Persistence Integration (Lesson 53):
    • Persist API request audit logs into an SQLite database table using parameterized SQL statements and sqlite3.Row.
  7. Security, Performance & Memory Hardening (Lesson 52):
    • Use __slots__ across core domain models for memory optimization.
    • Read API bearer tokens and host configurations from environment variables using os.environ.
  8. Packaging & Distribution Integration (Lesson 51):
    • Include a programmatically generated pyproject.toml package specification string and an argparse CLI entry point structure.
  9. Clean Code, Documentation & Refactoring (Lesson 50):
    • Apply SOLID principles, DRY, and Google Style Docstrings across all functions and classes.
  10. Testing & Quality Assurance (Lessons 47-48):
    • Include unit tests verified via pytest fixtures testing FastAPI endpoints.
  11. Asyncio & Concurrency Integration (Lessons 45-46):
    • Implement fully asynchronous path handlers (`async def`) and background event loops.
  12. Temporal & RegEx Text Processing (Lessons 43-44):
    • Parse UTC-aware timestamps using datetime and zoneinfo.ZoneInfo.
    • Pre-compile RegEx patterns with Named Groups for parsing HTTP URI paths.
  13. Type Hints, Generics & Static Safety (Lesson 42):
    • Apply explicit modern type annotations (X | Y, list[str], dict[str, Any]) throughout all functions and classes.
  14. Metaprogramming, Closures & Decorators (Lessons 40-41):
    • Build function factories and 3-level configurable decorators with @functools.wraps.
  15. Iterators & Generators (Lesson 39):
    • Implement generator functions streaming API event cursor rows lazily with $O(1)$ memory.
  16. Full OOP Architecture (Lessons 32-38):
    • Define abstract base class BaseFastAPIService(ABC) and concrete Data Classes FastAPIRouteRecord and WebhookAuditEntry.
    • Build composite manager FastAPIGatewayOS composing database persistence drivers and ASGI server handles.
  17. Observability & Fault Tolerance (Lessons 29-31):
    • Set up multi-handler logging to console and fastapi_gateway.log file.
    • Incorporate developer assertions (assert) verifying route response bounds.
    • Define custom exception hierarchy (FastAPIGatewayOSError, SchemaValidationError).
  18. Context Managers & Persistence Layer (Lessons 27-30):
    • Use custom class-based context managers to manage test client handles.
    • Persist JSON payload backups to fastapi_db.json and export CSV reports to fastapi_audit.csv using pathlib.Path.
  19. Nested Collections & Comprehensions (Lessons 21-26):
    • Maintain in-memory registry dictionaries mapping IDs to Data Class Instances.
    • Use List and Dictionary Comprehensions to clean and transform records.
  20. Advanced Function Parameters & Scope (Lessons 15-17):
    • Structure logic into pure modular functions with type hints, docstrings, early return Guard Clauses, and *args / **kwargs logging.
  21. Indefinite & Definite Loops (Lessons 13-14):
    • Run the interactive CLI interface inside a continuous while True menu loop.
    • Iterate through output reports using for loops with enumerate() and .items().
  22. Pattern Matching CLI Dispatcher (Lesson 12):
    • Process user CLI command tokens inside a match-case block with ASGI server match guards:
      • case ["TEST", "GET", route_path] → Simulate asynchronous GET request via FastAPI TestClient.
      • case ["TEST", "POST", route_path, json_str] → Simulate POST request with Pydantic JSON validation.
      • case ["AUDIT", "MODELS"] → Route Pydantic event models using match-case pattern dispatcher.
      • case ["EXPORT", "CSV"] → Export completed route access history to CSV.
      • case ["EXIT" | "QUIT"] → Terminate session safely using a sentinel flag.
      • case _ → Output command error message.
  23. Conditionals, Formatting & Foundations (Lessons 1-11):
    • Sanitize all inputs using .strip() and .upper().
    • Format tabular reports using f-strings with field width alignment specifiers (:<15, :>10) and clear visual borders.

9. File & Workspace Directory Structure

Standard Course Workspace Layout:

Ensure all exercise files are stored inside their corresponding lesson directories:

python_mastery_course/
│
├── lesson_01/ ... lesson_57/
│
└── lesson_58/
    ├── fastapi_basic_routing.py
    ├── pydantic_schema_validation.py
    ├── fastapi_dependency_injection_demo.py
    ├── match_case_fastapi_dispatcher.py
    ├── fastapi_books_task.py          <-- (Task 1)
    ├── fastapi_dispatcher_task.py     <-- (Task 2)
    └── fastapi_gateway_os.py          <-- (Task 3: Master Review Capstone)
        

10. What We Will Learn Next

Next Up: Lesson 59 — Data Analysis with NumPy and pandas

Congratulations on completing Module 10 and mastering Web Application Frameworks with Flask and FastAPI! We now enter Module 11: Scientific Computing, Data Science and Machine Learning!

In the next lesson, we will cover:

  • Introduction to Scientific Computing and Data Science in Python.
  • High-performance N-dimensional array processing using NumPy (`np.ndarray`).
  • Structured tabular data analysis using pandas DataFrames and Series.
  • Data Cleaning, Filtering, Missing Value Handling (`dropna()`, `fillna()`), and Grouping (`groupby()`).
  • Combining DataFrame record streams with match-case structural pattern matchers.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
Address Contact

+91 7877547686

E-mail

onlinecbtportal@gmail.com

Helpline Number

+91 7877547686


Click To Download
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat