6_FastAPI Notes

FastAPI

  • FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+.
  • It is based on standard Python type hints.
  • Designed for speed in both execution and development.

Key Features of FastAPI

  • Fast: High performance, comparable to NodeJS and Go, thanks to Starlette and Pydantic.
  • Easy to use: Intuitive design reducing bugs, with automatic data validation and interactive documentation.
  • Type-hinting support: Uses Python type hints for request parameters and JSON bodies.
  • Auto-generated documentation: Swagger UI and ReDoc are automatically generated.
  • Asynchronous support: Built with async/await for non-blocking code.
  • Data validation: Uses Pydantic models to enforce and validate data formats.

FastAPI vs Flask

FeatureFastAPIFlask
Created forModern, async, high-performance APIsSimplicity and flexibility, general web apps
Python versionPython 3.7+ (requires type hints)Python 2.7+ / 3.x (more broadly compatible)
Async supportNative async/await supportNot natively - needs workarounds or extensions
PerformanceVery fast (Starlette + async)Slower (sync only by default)
Type HintsFirst-class citizens - used for validation/docsOptional, not integrated
Data validationBuilt-in (Pydantic models)Manual or with marshmallow/wtforms
Automatic docsSwagger & ReDoc auto-generatedNot built-in (needs Flask-RESTPlus or similar)
Best forAPIs, microservices, async-heavy appsSimple web apps, quick scripts, classic MVC

FastAPI vs REST

  • FastAPI is a web framework known for speed and automatic documentation.
  • FastAPI helps build APIs that often follow RESTful principles.
  • FastAPI uses Python type hints for data validation and serialization.
  • It supports asynchronous programming for high performance.
  • REST is an architectural style for designing networked applications.
  • REST defines resource structure and access over HTTP, but doesn’t enforce specific implementation.
  • RESTful APIs can be asynchronous depending on the framework.

FastAPI vs Flask Code Examples

  • FastAPI

    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/hello")
    def read_hello(name: str):
        return {"message": f"Hello {name}"}
    
  • Flask

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route("/hello")
    def read_hello():
        name = request.args.get("name")
        return {"message": f"Hello {name}"}
    

Requirements

  • Python 3.7+ (Python 3.11+ recommended)
  • pip for installing packages
  • Optional: virtual environment for dependency isolation
  • A code editor (e.g., VS Code)

Installation

  • Install FastAPI and Uvicorn:

    pip install fastapi uvicorn
    

Uvicorn

  • Uvicorn is a lightweight ASGI server for running asynchronous Python web apps like those built with FastAPI.
  • FastAPI handles logic and routing.
  • Uvicorn handles communication between users and the app.
  • It listens for incoming requests, passes them to FastAPI, and sends responses back.

ASGI

  • Uvicorn is built on ASGI (Asynchronous Server Gateway Interface).
  • ASGI is a newer, powerful alternative to WSGI.
ASGI Features:
  • Async code (non-blocking)
  • WebSockets support
  • Better performance under load
Why use Uvicorn with FastAPI?
  • FastAPI is async-friendly and built for ASGI.
  • Uvicorn is a popular ASGI server.
  • It’s fast and production-ready.

Type Hints

  • Type hints specify expected data types for variables, function parameters, and return values using Python’s type annotations.
  • FastAPI relies on type hints to validate, serialize, and generate documentation.

Why Type Hints Matter in FastAPI

  • Validate request data (e.g., query parameters, path parameters, body data).
  • Generate automatic OpenAPI documentation.
  • Improve editor support (e.g., auto-completion, linting).
  • Deserialize and serialize data properly.

Data Types

  • str: Represents a string of text.
  • int: Represents an integer number.
  • float: Represents a decimal or floating-point number.
  • bool: Represents a boolean value (True or False).
  • Optional[X]: Indicates a value that can be of type X or None.
  • List[X]: A list containing items of type X.
  • Dict[K, V]: A dictionary with keys of type K and values of type V.
  • Union[X, Y]: A value that can be of type X or Y.
  • BaseModel: A Pydantic model used for structured request or response bodies.

Example: Query Parameters

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/")
def read_item(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

Example: Path Parameters

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

Example: Body Parameters with Pydantic

from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class Product(BaseModel):
    name: str
    price: float
    tags: list[str]
    in_stock: bool

@app.post("/products/")
def create_product(product: Product):
    return {"product": product}

Async

  • You can define endpoint functions using async def to handle multiple requests asynchronously.
  • async def declares an asynchronous function.
  • Lets your app pause while waiting (e.g., for a database call), so other requests can be served in the meantime.
  • Great for I/O-bound operations (like calling APIs, databases, etc.).
  • Synchronous (def) functions block the app until finished.
  • Asynchronous (async def) functions don't block—they can "pause" and let other tasks run while waiting.

Example:

from fastapi import FastAPI
from pydantic import BaseModel
import asyncio  # Optional: to simulate delay

app = FastAPI()

# Pydantic model for POST body
class Item(BaseModel):
    name: str
    price: float

# Async GET endpoint
@app.get("/ping")
async def ping():
    await asyncio.sleep(1)  # Simulates a delay, like calling a database
    return {"message": "pong"}

# Async POST endpoint
@app.post("/items/")
async def create_item(item: Item):
    await asyncio.sleep(1)  # Simulates some processing delay
    return item

Task

  • A task refers to an asynchronous operation or background task that is executed without blocking the main thread or process.
  • Allows the application to continue handling other requests.
  • FastAPI provides built-in support for asynchronous tasks via Python's asyncio library.
  • Tasks are used for background jobs, scheduled tasks, or time-consuming operations outside of the request-response cycle.

1. Background Tasks in FastAPI

  • FastAPI has a feature called Background Tasks to run code in the background without delaying the response.
  • Useful for tasks like sending emails, logging, or processing large amounts of data, while giving the user an immediate response.

2. Asynchronous Tasks with async/await

  • FastAPI supports asynchronous operations using Python’s async and await syntax.
  • When you define an endpoint with async def, the handler function can perform asynchronous tasks without blocking the main thread.
  • Examples: making HTTP requests, querying a database, or performing file I/O operations.

3. Using Task Queues (e.g., Celery)

  • For more complex background task handling, use a task queue like Celery.
  • Celery allows you to distribute tasks across workers, retry tasks on failure, and manage task results.
  • FastAPI can be integrated with Celery for task processing.

Validation

  • FastAPI uses Pydantic models for request body validation, query parameters, and more.
  • It automatically validates the incoming data and gives meaningful error messages.
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    is_offer: bool = False  # Optional with default

@app.post("/items/")
async def create_item(item: Item):
    return {"item": item}
  • If a client sends invalid JSON (e.g., missing fields or wrong types), FastAPI will return a 422 Unprocessable Entity response with a structured error.

Error Handling

  • You can handle errors globally using exception handlers.
  • FastAPI gives you built-in exceptions like HTTPException, and you can create custom ones too.
from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id != 42:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item_id": item_id}