FASTAPI Framework Development

By Himanshu Shekhar | 04 Feb 2022 | (0 Reviews)

Suggest Improvement on FastAPI Framework Development β€” Click here



Python & FastAPI Foundations – Deep Dive

FastAPI is a modern, high-performance web framework for building APIs with Python based on standard Python type hints. In this comprehensive module from NotesTime.in, you'll gain deep understanding of FastAPI internals, Python async execution model, ASGI architecture, and production-ready setup. This foundation is crucial for professional FastAPI development.


1.1 What is FastAPI & Why It's High Performance

FastAPI is a modern web framework for building APIs with Python 3.7+ based on standard Python type hints. Created by SebastiΓ‘n RamΓ­rez in 2018, it's designed to be fast, intuitive, and production-ready.

Key Features:
  • ⚑ High Performance: On par with Node.js and Go (thanks to Starlette and Pydantic)
  • πŸ“ Type Hints: Leverages Python type hints for automatic validation and serialization
  • πŸ“š Automatic Documentation: Interactive API docs (Swagger UI, ReDoc) out of the box
  • πŸ” Validation: Request/response validation using Pydantic models
  • 🧩 Dependency Injection: Powerful DI system for clean, testable code
  • 🌐 Async Support: Native async/await for high concurrency
  • πŸ”’ Security: Built-in support for OAuth2, JWT, HTTP Basic Auth
Performance Benchmarks:
Framework Requests/sec Technology
FastAPI ~70,000 Python/ASGI
Node.js (Express) ~65,000 JavaScript
Go (Gin) ~95,000 Go
Flask ~8,000 Python/WSGI
πŸ’‘ Real-World Usage: Microsoft (for some Azure services), Uber, Netflix, and thousands of startups use FastAPI for high-performance microservices.

1.2 Python Execution Model & Async Basics

Python Execution Model:

Python code is compiled to bytecode, then executed by the Python Virtual Machine (PVM).

Synchronous vs Asynchronous:
  • Synchronous (Blocking): Operations execute sequentially, blocking until complete
  • Asynchronous (Non-blocking): Operations can run concurrently using an event loop
Async/Await Keywords:
# Synchronous function
def get_data():
    return fetch_from_database()  # Blocks until complete

# Asynchronous function
async def get_data_async():
    data = await fetch_from_database_async()  # Non-blocking
    return data
Event Loop Explained:

The event loop continuously checks for I/O events and executes coroutines when ready:

  1. Register coroutines with event loop
  2. When await is encountered, control returns to event loop
  3. Event loop handles other tasks while waiting
  4. When I/O completes, coroutine resumes
⚠ Remember: Async doesn't make CPU-bound code faster - it's for I/O-bound operations like database calls, API requests, file operations.

1.3 ASGI vs WSGI (FastAPI vs Django/Flask)

WSGI (Web Server Gateway Interface):

Standard for Python web apps (PEP 3333) - synchronous only, one request at a time per worker.

ASGI (Asynchronous Server Gateway Interface):

Successor to WSGI supporting async operations, WebSockets, HTTP/2 (specified in ASGI specification).

Feature WSGI ASGI
Protocol Support HTTP only HTTP, HTTP/2, WebSockets, gRPC
Concurrency Process/thread based Event-driven, single-threaded async
Long-lived connections Not suitable Perfect for WebSockets, SSE
Examples Flask, Django (traditional) FastAPI, Starlette, Django (ASGI mode)
Performance Good for simple apps Excellent for high concurrency
βœ… FastAPI (ASGI) can handle 10,000+ concurrent connections, while WSGI frameworks typically max out at a few hundred per worker.

1.4 FastAPI Project Structure (App, Routers, Core)

A professional FastAPI project follows clean architecture principles:

my_fastapi_project/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ main.py                 # Application entry point
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ config.py           # Pydantic settings
β”‚   β”‚   β”œβ”€β”€ security.py          # Auth, JWT, password hashing
β”‚   β”‚   β”œβ”€β”€ database.py          # DB connection, session
β”‚   β”‚   └── dependencies.py      # Global dependencies
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ v1/
β”‚   β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ users.py
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ items.py
β”‚   β”‚   β”‚   β”‚   └── auth.py
β”‚   β”‚   β”‚   └── endpoints/
β”‚   β”‚   └── deps.py              # API-specific dependencies
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ user.py              # SQLAlchemy models
β”‚   β”‚   └── item.py
β”‚   β”œβ”€β”€ schemas/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ user.py              # Pydantic schemas
β”‚   β”‚   └── item.py
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ user_service.py      # Business logic
β”‚   β”‚   └── item_service.py
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   └── helpers.py
β”‚   └── static/                   # Static files
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ conftest.py
β”‚   β”œβ”€β”€ test_api/
β”‚   └── test_services/
β”œβ”€β”€ alembic/                       # Database migrations
β”œβ”€β”€ .env                           # Environment variables
β”œβ”€β”€ .env.example                   # Example env vars
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ requirements-dev.txt
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
└── README.md
πŸ’‘ This structure follows separation of concerns - routes handle HTTP, services handle business logic, models define data structure, and schemas validate data.

1.5 FastAPI Request Lifecycle

Understanding how FastAPI processes a request is crucial for debugging and optimization:

Complete Request Flow:
  1. Client Request β†’ HTTP request sent to server
  2. ASGI Server (Uvicorn) β†’ Receives request, creates ASGI scope
  3. ASGI Application (FastAPI) β†’ Receives scope, receive, send
  4. Middleware Stack (Top→Bottom) → Each middleware processes request
  5. Route Matching β†’ FastAPI matches path to path operation
  6. Dependency Resolution β†’ All dependencies resolved (may include sub-dependencies)
  7. Parameter Extraction β†’ Extract path, query, body, headers
  8. Validation β†’ Validate data against Pydantic models
  9. Path Operation Function β†’ Execute endpoint logic
  10. Response Preparation β†’ Convert return value to response
  11. Response Validation β†’ Validate response against response_model
  12. Middleware Stack (Bottom→Top) → Each middleware processes response
  13. ASGI Response β†’ Send response back to client
⚠ Middleware order matters! Request goes through middleware in the order they're added, response goes in reverse order.

1.6 Dependency Injection System (Depends Deep Dive)

FastAPI's dependency injection system is one of its most powerful features:

What is Dependency Injection?

Design pattern where objects receive their dependencies from an external source rather than creating them internally.

Basic Dependency:
from fastapi import Depends, FastAPI, Query

app = FastAPI()

# Dependency function
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}

# Using the dependency
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    return commons

@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
    return commons
Class-based Dependencies:
from fastapi import Depends

class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit

@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends()):
    return commons
Nested Dependencies:
from fastapi import Depends, HTTPException, status
from typing import Annotated

async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
    user = fake_decode_token(token)
    if not user:
        raise HTTPException(status_code=401)
    return user

async def get_current_active_user(
    current_user: Annotated[User, Depends(get_current_user)]
):
    if current_user.disabled:
        raise HTTPException(status_code=400)
    return current_user

@app.get("/users/me")
async def read_users_me(
    current_user: Annotated[User, Depends(get_current_active_user)]
):
    return current_user
🧠 Benefits: Code reuse, testability, separation of concerns, and automatic documentation.

1.7 Installing FastAPI (pip, uvicorn, poetry)

Using pip (Traditional):
# Core installation
pip install fastapi

# ASGI server
pip install "uvicorn[standard]"

# Optional dependencies
pip install python-multipart  # For form data
pip install jinja2            # For templates
pip install python-jose[cryptography]  # For JWT
pip install passlib[bcrypt]   # For password hashing
pip install aiofiles          # For async file operations

# Development dependencies
pip install pytest            # Testing
pip install httpx             # Async HTTP client for testing
pip install black             # Code formatting
pip install ruff              # Linting
Using requirements.txt:
# requirements.txt
fastapi==0.104.1
uvicorn[standard]==0.24.0
python-multipart==0.0.6
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
pydantic-settings==2.0.3
python-dotenv==1.0.0

# Install with: pip install -r requirements.txt
Using Poetry (Modern):
# Install poetry
curl -sSL https://install.python-poetry.org | python3

# Create new project
poetry new my-fastapi-project
cd my-fastapi-project

# Add dependencies
poetry add fastapi uvicorn[standard] python-multipart
poetry add --dev pytest pytest-asyncio httpx

# Activate environment
poetry shell
Using pipenv:
pip install pipenv
pipenv install fastapi uvicorn[standard]
pipenv install --dev pytest
pipenv shell

1.8 Environment Configuration (.env, pydantic-settings)

FastAPI uses Pydantic Settings for type-safe environment configuration:

.env file:
# .env (never commit to git)
APP_NAME="My FastAPI App"
APP_VERSION="1.0.0"
DEBUG=True
SECRET_KEY="your-secret-key-here"

DATABASE_URL="postgresql://user:pass@localhost/dbname"
REDIS_URL="redis://localhost:6379/0"

JWT_SECRET_KEY="jwt-secret-key"
JWT_ALGORITHM="HS256"
JWT_EXPIRATION_MINUTES=30

CORS_ORIGINS=["http://localhost:3000", "https://example.com"]

EMAIL_HOST="smtp.gmail.com"
EMAIL_PORT=587
EMAIL_USER="user@gmail.com"
EMAIL_PASSWORD="app-password"
Pydantic Settings (config.py):
from pydantic_settings import BaseSettings
from pydantic import ConfigDict, Field
from typing import List

class Settings(BaseSettings):
    # App settings
    app_name: str = "FastAPI App"
    app_version: str = "1.0.0"
    debug: bool = False
    secret_key: str
    
    # Database
    database_url: str
    
    # Redis
    redis_url: str = "redis://localhost:6379/0"
    
    # JWT
    jwt_secret_key: str
    jwt_algorithm: str = "HS256"
    jwt_expiration_minutes: int = 30
    
    # CORS
    cors_origins: List[str] = ["http://localhost:3000"]
    
    # Email
    email_host: str | None = None
    email_port: int = 587
    email_user: str | None = None
    email_password: str | None = None
    
    model_config = ConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False
    )

settings = Settings()  # Automatically loads from .env
Using settings in main.py:
from fastapi import FastAPI
from app.core.config import settings

app = FastAPI(
    title=settings.app_name,
    version=settings.app_version,
    debug=settings.debug
)

@app.get("/info")
async def info():
    return {
        "app_name": settings.app_name,
        "version": settings.app_version,
        "debug": settings.debug
    }
🚨 Never commit .env files to Git! Add .env to .gitignore and provide .env.example as a template.

1.9 Uvicorn, Gunicorn & Server Concepts

Uvicorn (ASGI Server):

A lightning-fast ASGI server implementation, using uvloop and httptools.

# Basic usage
uvicorn main:app

# With hot reload (development)
uvicorn main:app --reload

# Custom host and port
uvicorn main:app --host 0.0.0.0 --port 8000

# With SSL
uvicorn main:app --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem

# With log level
uvicorn main:app --log-level debug

# Production settings
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 --limit-max-requests 1000
Gunicorn + Uvicorn (Production):

Gunicorn acts as a process manager with Uvicorn workers:

# Install
pip install gunicorn uvicorn

# Run with Uvicorn workers
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker

# With more options
gunicorn main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 120 \
    --max-requests 1000 \
    --max-requests-jitter 100 \
    --access-logfile - \
    --error-logfile -
Comparison of ASGI Servers:
Server Best For Features
Uvicorn Development, simple production Fast, lightweight, HTTP/1.1 and WebSocket
Hypercorn HTTP/2, HTTP/3 support HTTP/2, HTTP/3, Trio support
Daphne Django Channels HTTP/1.1, WebSocket support

1.10 Starlette Internals (FastAPI Base)

FastAPI is built on top of Starlette, inheriting its performance and features:

What FastAPI inherits from Starlette:
  • 🌐 WebSocket support
  • πŸ“‘ GraphQL support
  • πŸ”„ Background tasks
  • πŸ›£οΈ Routing system
  • 🧩 Middleware framework
  • πŸ“ Static files serving
  • πŸ§ͺ Test client
  • πŸ”§ Request/Response objects
What FastAPI adds:
  • πŸ“ Data validation (Pydantic)
  • πŸ” Dependency injection system
  • πŸ“š Automatic API docs (Swagger, ReDoc)
  • 🎯 Type hints integration
  • βœ… Request/response validation
# Starlette example
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

async def homepage(request):
    return JSONResponse({'hello': 'world'})

routes = [
    Route('/', homepage),
]

app = Starlette(routes=routes)

# FastAPI equivalent (with validation)
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.post("/")
async def create_item(item: Item):
    return {"item": item}

1.11 ASGI Scope, Receive & Send

ASGI applications are async callables that receive scope, receive, and send:

ASGI Specification:
async def app(scope, receive, send):
    # scope: Connection information (type, path, headers)
    # receive: Async function to receive messages
    # send: Async function to send messages
    pass
HTTP Scope Example:
{
    "type": "http",
    "http_version": "1.1",
    "method": "GET",
    "path": "/items/1",
    "query_string": b"",
    "headers": [
        (b"host", b"localhost:8000"),
        (b"user-agent", b"curl/7.68.0"),
        (b"accept", b"*/*")
    ]
}
WebSocket Scope:
{
    "type": "websocket",
    "path": "/ws/chat",
    "headers": [...],
    "subprotocols": ["chat"]
}
Simple ASGI App:
async def simple_app(scope, receive, send):
    if scope["type"] == "http":
        await send({
            "type": "http.response.start",
            "status": 200,
            "headers": [
                [b"content-type", b"text/plain"],
            ]
        })
        await send({
            "type": "http.response.body",
            "body": b"Hello, ASGI!",
        })

1.12 Middleware Internals (Custom Middleware)

Middleware in FastAPI processes requests before they reach endpoints and responses before they're sent:

Base Middleware Pattern:
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import time

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # Pre-processing
        start_time = time.time()
        
        # Call next middleware/endpoint
        response = await call_next(request)
        
        # Post-processing
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)
        
        return response

# Add middleware to app
app = FastAPI()
app.add_middleware(TimingMiddleware)
Request ID Middleware:
import uuid
from starlette.middleware.base import BaseHTTPMiddleware

class RequestIDMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
        request.state.request_id = request_id
        
        response = await call_next(request)
        response.headers["X-Request-ID"] = request_id
        
        return response
Authentication Middleware:
from fastapi import HTTPException
import jwt

class AuthMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # Skip auth for public paths
        if request.url.path in ["/", "/docs", "/openapi.json"]:
            return await call_next(request)
        
        # Check authorization header
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Bearer "):
            raise HTTPException(status_code=401)
        
        try:
            token = auth_header.split(" ")[1]
            payload = jwt.decode(token, "secret", algorithms=["HS256"])
            request.state.user = payload
        except:
            raise HTTPException(status_code=401)
        
        return await call_next(request)
Middleware Order:
app.add_middleware(TimingMiddleware)    # Executes first
app.add_middleware(RequestIDMiddleware)  # Executes second
app.add_middleware(AuthMiddleware)       # Executes third

# Request: Timing β†’ RequestID β†’ Auth β†’ Endpoint
# Response: Endpoint β†’ Auth β†’ RequestID β†’ Timing

1.13 FastAPI Full Setup (Dev β†’ Production)

Development Setup:
# 1. Create project directory
mkdir my-fastapi-app && cd my-fastapi-app

# 2. Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# 3. Install dependencies
pip install fastapi uvicorn[standard] python-multipart

# 4. Create main.py
# (basic FastAPI app code)
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def home():
    return {"message": "Working βœ…"}

# 5. Run development server
python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000    # On Windows

OR

python -m uvicorn main:app --reload  # On Windows
Production Setup:
# 1. Install production dependencies
pip install gunicorn httptools uvloop

# 2. Create .env file with production settings
# (database URLs, secrets, etc.)

# 3. Run with Gunicorn + Uvicorn workers
gunicorn main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:8000 \
    --timeout 120 \
    --access-logfile - \
    --error-logfile -

# 4. Or use process manager like Supervisor
sudo apt-get install supervisor
# Configure /etc/supervisor/conf.d/fastapi.conf
Production Checklist:
  • βœ… Use environment variables for secrets
  • βœ… Enable HTTPS (SSL/TLS)
  • βœ… Set up proper logging
  • βœ… Configure CORS properly
  • βœ… Use connection pooling for databases
  • βœ… Set up monitoring (Prometheus, Grafana)
  • βœ… Implement rate limiting
  • βœ… Use CDN for static files

1.14 Virtual Environment & Dependency Management

Python venv:
# Create virtual environment
python -m venv venv

# Activate (Linux/Mac)
source venv/bin/activate

# Activate (Windows)
venv\Scripts\activate

# Deactivate
deactivate

# Export dependencies
pip freeze > requirements.txt

# Install from requirements
pip install -r requirements.txt
Pipenv:
# Install
pip install pipenv

# Create environment and install packages
pipenv install fastapi uvicorn[standard]

# Install dev dependencies
pipenv install --dev pytest black

# Activate environment
pipenv shell

# Generate requirements.txt
pipenv requirements > requirements.txt
Poetry:
# Create new project
poetry new myproject
cd myproject

# Add dependencies
poetry add fastapi uvicorn[standard]
poetry add --dev pytest pytest-asyncio httpx

# Activate environment
poetry shell

# Export requirements.txt
poetry export -f requirements.txt --output requirements.txt

1.15 Project Structure (Clean Architecture Setup)

Clean Architecture separates concerns into layers:

clean_fastapi_project/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ domain/                      # Enterprise-wide business rules
β”‚   β”‚   β”œβ”€β”€ entities/                 # Business objects
β”‚   β”‚   β”‚   β”œβ”€β”€ user.py
β”‚   β”‚   β”‚   └── product.py
β”‚   β”‚   β”œβ”€β”€ value_objects/            # Immutable objects
β”‚   β”‚   └── interfaces/                # Repository interfaces
β”‚   β”œβ”€β”€ application/                  # Application business rules
β”‚   β”‚   β”œβ”€β”€ use_cases/                 # Business use cases
β”‚   β”‚   β”‚   β”œβ”€β”€ create_user.py
β”‚   β”‚   β”‚   └── get_product.py
β”‚   β”‚   β”œβ”€β”€ dto/                       # Data Transfer Objects
β”‚   β”‚   └── services/                   # Application services
β”‚   β”œβ”€β”€ infrastructure/                # Frameworks & drivers
β”‚   β”‚   β”œβ”€β”€ database/                   
β”‚   β”‚   β”‚   β”œβ”€β”€ models/                 # SQLAlchemy models
β”‚   β”‚   β”‚   β”œβ”€β”€ repositories/           # Repository implementations
β”‚   β”‚   β”‚   └── migrations/
β”‚   β”‚   β”œβ”€β”€ external_apis/              # Third-party API clients
β”‚   β”‚   └── cache/                      # Redis clients
β”‚   β”œβ”€β”€ api/                            # Interface adapters
β”‚   β”‚   β”œβ”€β”€ routes/                     # FastAPI routes
β”‚   β”‚   β”œβ”€β”€ middlewares/                 # Custom middleware
β”‚   β”‚   β”œβ”€β”€ dependencies/                # Dependency injection
β”‚   β”‚   └── schemas/                     # Pydantic schemas
β”‚   └── core/                           # Core configuration
β”‚       β”œβ”€β”€ config.py
β”‚       β”œβ”€β”€ security.py
β”‚       └── exceptions.py
β”œβ”€β”€ tests/                               # Test modules
β”œβ”€β”€ .env
β”œβ”€β”€ pyproject.toml
└── README.md
πŸ’‘ Clean Architecture ensures that business logic is independent of frameworks, databases, and external APIs.

1.16 Running FastAPI (Uvicorn & Dev Server)

Basic Commands:
# Run with default settings
uvicorn main:app

# With hot reload (development)
uvicorn main:app --reload

# Custom host and port
uvicorn main:app --host 0.0.0.0 --port 8080

# With SSL
uvicorn main:app --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem

# With log level
uvicorn main:app --log-level debug --reload

# With factory pattern
uvicorn main:create_app --factory --reload

# With environment variables
uvicorn main:app --env-file .env.local
Python Script Method:
# run.py
import uvicorn

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info",
        workers=1
    )
Using with Docker:
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

1.17 Environment Variables & Config Management

Multiple Environment Support:
# config.py
from pydantic_settings import BaseSettings
from functools import lru_cache

class Settings(BaseSettings):
    environment: str = "development"
    database_url: str
    redis_url: str
    secret_key: str
    
    class Config:
        env_file = ".env"

class DevelopmentSettings(Settings):
    debug: bool = True
    reload: bool = True

class ProductionSettings(Settings):
    debug: bool = False
    reload: bool = False

@lru_cache()
def get_settings():
    env = os.getenv("ENVIRONMENT", "development")
    if env == "production":
        return ProductionSettings()
    return DevelopmentSettings()

settings = get_settings()
.env files structure:
# .env.development
DATABASE_URL=postgresql://localhost/dev_db
REDIS_URL=redis://localhost:6379/0
DEBUG=True
SECRET_KEY=dev-secret-key

# .env.production
DATABASE_URL=postgresql://prod:pass@prod-db/prod_db
REDIS_URL=redis://redis-cluster:6379/0
DEBUG=False
SECRET_KEY=${PROD_SECRET_KEY}

1.18 Production Setup (Gunicorn + Uvicorn Workers)

Gunicorn Configuration File:
# gunicorn.conf.py
import multiprocessing

bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"
timeout = 120
keepalive = 5
max_requests = 1000
max_requests_jitter = 100

# Logging
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
loglevel = "info"

# SSL (if terminating at Gunicorn)
# keyfile = "/etc/ssl/private/key.pem"
# certfile = "/etc/ssl/certs/cert.pem"

# Preload app
preload_app = True

def on_starting(server):
    """Log when server starts"""
    server.log.info("Starting FastAPI application")

def on_exit(server):
    """Log when server exits"""
    server.log.info("Stopping FastAPI application")
Running with configuration:
# Using config file
gunicorn -c gunicorn.conf.py main:app

# Or command line
gunicorn main:app \
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --bind unix:/tmp/gunicorn.sock \
    --daemon \
    --pid /var/run/gunicorn.pid

1.19 Dockerizing FastAPI Application

Multi-stage Dockerfile:
# Dockerfile
# Build stage
FROM python:3.11-slim as builder

WORKDIR /app

COPY requirements.txt .
RUN pip install --user -r requirements.txt

# Runtime stage
FROM python:3.11-slim

WORKDIR /app

# Create non-root user
RUN useradd -m -u 1000 fastapi && \
    chown -R fastapi:fastapi /app

# Copy Python dependencies
COPY --from=builder /root/.local /home/fastapi/.local
ENV PATH=/home/fastapi/.local/bin:$PATH

# Copy application
COPY --chown=fastapi:fastapi . .

USER fastapi

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose:
# docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/fastapi
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - db
      - redis
    volumes:
      - ./:/app
    command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=fastapi
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:
Build and run:
# Build image
docker build -t fastapi-app .

# Run container
docker run -p 8000:8000 fastapi-app

# With docker-compose
docker-compose up -d

# Scale workers
docker-compose up -d --scale api=3

1.20 Nginx Reverse Proxy Setup

Nginx Configuration:
# /etc/nginx/sites-available/fastapi
upstream fastapi_backend {
    least_conn;  # Load balancing strategy
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 80;
    server_name api.example.com;
    
    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;
    
    # SSL certificates
    ssl_certificate /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Logs
    access_log /var/log/nginx/fastapi_access.log;
    error_log /var/log/nginx/fastapi_error.log;
    
    # Large file uploads
    client_max_body_size 100M;
    
    location / {
        proxy_pass http://fastapi_backend;
        proxy_http_version 1.1;
        
        # Headers
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # Static files (if any)
    location /static {
        alias /var/www/fastapi/static;
        expires 30d;
    }
}
Enable and test:
# Enable site
ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/

# Test configuration
nginx -t

# Reload Nginx
systemctl reload nginx

# Check logs
tail -f /var/log/nginx/fastapi_error.log

1.21 Deployment (AWS / VPS / Cloud Platforms)

AWS EC2 Deployment:
# 1. Launch EC2 instance (Ubuntu 22.04)
# 2. SSH into instance
ssh -i key.pem ubuntu@ec2-xx-xx-xx-xx.compute-1.amazonaws.com

# 3. Install dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install python3-pip python3-venv nginx -y

# 4. Clone repository
git clone https://github.com/yourusername/fastapi-app.git
cd fastapi-app

# 5. Setup environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 6. Create .env file
nano .env

# 7. Setup systemd service
sudo nano /etc/systemd/system/fastapi.service
Systemd Service File:
[Unit]
Description=FastAPI Application
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/fastapi-app
Environment="PATH=/home/ubuntu/fastapi-app/venv/bin"
ExecStart=/home/ubuntu/fastapi-app/venv/bin/gunicorn -c gunicorn.conf.py main:app
Restart=always

[Install]
WantedBy=multi-user.target
Deploy with GitHub Actions:
# .github/workflows/deploy.yml
name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to EC2
        uses: appleboy/ssh-action@v0.1.5
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ubuntu
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            cd /home/ubuntu/fastapi-app
            git pull origin main
            source venv/bin/activate
            pip install -r requirements.txt
            sudo systemctl restart fastapi
            sudo systemctl status fastapi
Alternative Platforms:
  • Heroku: Procfile with "web: uvicorn main:app --host 0.0.0.0 --port $PORT"
  • DigitalOcean App Platform: Connect GitHub repo, auto-deploy
  • Railway: Automatic deployments with GitHub integration
  • Fly.io: Global deployment with fly.toml configuration
  • Google Cloud Run: Container-based serverless deployment
  • Azure App Service: Configure startup command
πŸš€ Pro tip: Use infrastructure as code (Terraform, CloudFormation) for reproducible deployments.

πŸŽ“ Module 01 : Python & FastAPI Foundations (Deep) Successfully Completed

You have successfully completed this module of FastAPI Framework Development.

Keep building your expertise step by step β€” Learn Next Module β†’