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 β†’


Project Deployment - AWS, GCP, Azure & More

Complete deployment guide for hosting FastAPI applications on major cloud platforms. This comprehensive module covers everything from basic VPS setup to advanced serverless and Kubernetes deployments with production-ready configurations for EduHack-Lab and similar FastAPI projects.


17.1 AWS Deployment (EC2, ECS, Lambda, Elastic Beanstalk)

πŸ“š What You'll Learn in This Section

  • βœ… Deploy any FastAPI project to AWS EC2 (Free Tier eligible)
  • βœ… Configure production-ready environment with Nginx + Gunicorn
  • βœ… Set up automatic service restart on server reboot
  • βœ… Alternative deployment methods (Elastic Beanstalk, Lambda, ECS)

πŸ’° Understanding AWS Free Tier

πŸ’° AWS Free Tier Includes:
  • πŸ–₯️ 750 hours/month of t2.micro EC2 instance (enough for 24/7 operation)
  • πŸ’Ύ 30 GB of EBS storage
  • πŸ“Š 1 million API requests via API Gateway
  • πŸ—„οΈ 20 GB of RDS database storage (optional)
  • ⏰ Valid for 12 months from account creation

πŸ“‹ Prerequisites - What You Need Before Starting

βœ… Account & Access
  • AWS account (signup: aws.amazon.com)
  • Credit card for verification (no charges for free tier)
  • Phone number for verification
βœ… Your FastAPI Project
  • Working FastAPI project on local machine
  • requirements.txt file with all dependencies
  • GitHub repository (recommended for easy transfer)
  • Basic knowledge of terminal/command line

πŸš€ Step-by-Step Deployment Guide for Any FastAPI Project

Step 1: Create an AWS Account (If you don't have one)
1. Go to https://aws.amazon.com
2. Click "Create an AWS Account"
3. Enter your email address and account name
4. Choose "Personal" account type
5. Enter payment information (no charges for free tier usage)
6. Verify your phone number
7. Choose "Basic" support plan (free)
8. Wait for account activation (usually 5-10 minutes)
Step 2: Launch Your EC2 Instance (Virtual Server)
πŸ“Œ Step-by-Step Console Instructions:

1. Login to AWS Console (console.aws.amazon.com)
2. Search for "EC2" in top search bar and click
3. Click the orange "Launch Instance" button
4. Fill in these settings:

   πŸ”Ή NAME YOUR INSTANCE:
      - Name: "my-fastapi-app" (or any name you prefer)
   
   πŸ”Ή CHOOSE OS IMAGE:
      - Click "Ubuntu"
      - Select "Ubuntu 22.04 LTS (HVM)" - Free tier eligible
   
   πŸ”Ή CHOOSE INSTANCE TYPE:
      - Select "t2.micro" (free tier eligible)
   
   πŸ”Ή KEY PAIR (LOGIN):
      - Click "Create new key pair"
      - Key pair name: "fastapi-key"
      - Key pair type: "RSA"
      - Private key format: ".pem"
      - Click "Create key pair" (file downloads automatically)
      - ⚠️ SAVE THIS FILE SAFELY! You'll need it to connect
   
   πŸ”Ή NETWORK SETTINGS (Security Group - Firewall):
      - Click "Edit"
      - Add these rules one by one:
        
        Rule 1 (SSH - to connect to server):
        - Type: SSH
        - Source: My IP (auto-detects your IP)
        - This allows YOU to connect securely
        
        Rule 2 (HTTP - for web access):
        - Click "Add security group rule"
        - Type: HTTP
        - Source: Anywhere-IPv4 (0.0.0.0/0)
        - This allows everyone to visit your website
        
        Rule 3 (Custom for FastAPI testing):
        - Click "Add security group rule"
        - Type: Custom TCP
        - Port: 8000
        - Source: Anywhere-IPv4 (0.0.0.0/0)
        - This allows testing on port 8000
   
   πŸ”Ή STORAGE:
      - Keep default: 20 GB gp2 (free tier includes 30 GB)
   
6. Click "Launch Instance" button
7. Wait 1-2 minutes for instance to start
8. Note down the "Public IPv4 address" (e.g., 54.123.45.67)
Step 3: Connect to Your EC2 Instance
πŸ“Œ For Windows Users:
Option A: Using PowerShell (Recommended)
1. Open PowerShell (Search in Start Menu)
2. Navigate to where you saved your .pem file:
   cd C:\Users\YourName\Downloads
3. Connect using this command:
   ssh -i "fastapi-key.pem" ubuntu@YOUR_SERVER_IP
   (Replace YOUR_SERVER_IP with actual IP from Step 2)

Option B: Using Git Bash
1. Install Git for Windows (git-scm.com)
2. Open Git Bash
3. Navigate to .pem folder:
   cd /c/Users/YourName/Downloads
4. Run:
   ssh -i "fastapi-key.pem" ubuntu@YOUR_SERVER_IP
πŸ“Œ For Mac/Linux Users:
1. Open Terminal
2. Navigate to .pem file location:
   cd ~/Downloads
3. Fix permissions (required):
   chmod 400 fastapi-key.pem
4. Connect:
   ssh -i "fastapi-key.pem" ubuntu@YOUR_SERVER_IP

βœ… Success! You should see: ubuntu@ip-xxx-xxx:~$
Step 4: Install Required Software on Server

Once connected to your server, run these commands one by one:

# 1. Update system packages (always do this first)
sudo apt update && sudo apt upgrade -y

# 2. Install Python and essential tools
sudo apt install -y python3-pip python3-venv git nginx curl

# 3. Verify installations
python3 --version    # Should show Python 3.10+
pip3 --version       # Should show pip version
git --version        # Should show git version
nginx -v             # Should show nginx version

# 4. Install production server (Gunicorn)
pip3 install gunicorn
Step 5: Upload Your FastAPI Code to Server
Option A: Using Git (EASIEST - Recommended)
πŸ“€ On YOUR Local Machine (First Time Setup):
# Navigate to your FastAPI project
cd your-fastapi-project

# Initialize Git repository
git init

# Add all files
git add .
git add .gitignore  # If you have one

# Commit the files
git commit -m "Initial FastAPI application commit"

# Add remote repository (replace with your GitHub URL)
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO.git

# Push to GitHub
git push -u origin main
# OR if using master branch:
git push -u origin master
πŸ“₯ On Your EC2 Server (Clone the Repository):
# Clone public repository
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd YOUR_REPO

# For private repository (using token):
git clone https://YOUR_USERNAME:YOUR_GITHUB_TOKEN@github.com/YOUR_USERNAME/YOUR_REPO.git

# For private repository (using SSH):
git clone git@github.com:YOUR_USERNAME/YOUR_REPO.git
πŸ”„ Update Existing Code (After Changes):
# On your local machine:
git add .
git commit -m "Describe your changes"
git push

# On EC2 server:
git pull
Option B: Upload files directly using SCP
# On YOUR LOCAL machine (open a new terminal):

# Upload entire project folder
scp -i "fastapi-key.pem" -r ./your-fastapi-project ubuntu@YOUR_SERVER_IP:~/

# Example:
scp -i "fastapi-key.pem" -r ./my-fastapi-app ubuntu@54.123.45.67:~/

# Upload specific files only
scp -i "fastapi-key.pem" main.py requirements.txt ubuntu@YOUR_SERVER_IP:~/my-fastapi-app/

# Upload with compression (faster for large files)
scp -i "fastapi-key.pem" -C -r ./your-fastapi-project ubuntu@YOUR_SERVER_IP:~/

# On your EC2 server, navigate to the project:
cd ~/your-fastapi-project
Option C: Using Rsync (Best for Large Projects & Syncing)
# On YOUR LOCAL machine:

# Sync entire project (only uploads changed files)
rsync -avz -e "ssh -i fastapi-key.pem" ./your-fastapi-project/ ubuntu@YOUR_SERVER_IP:~/your-fastapi-project/

# Exclude specific folders (like venv, __pycache__, .git)
rsync -avz --exclude 'venv' --exclude '__pycache__' --exclude '.git' \
    -e "ssh -i fastapi-key.pem" ./your-fastapi-project/ ubuntu@YOUR_SERVER_IP:~/your-fastapi-project/

# Dry run (see what would be transferred without actually doing it)
rsync -avz --dry-run -e "ssh -i fastapi-key.pem" ./your-fastapi-project/ ubuntu@YOUR_SERVER_IP:~/your-fastapi-project/
Option D: Using SFTP Client (FileZilla / WinSCP)
πŸ“Œ FileZilla Setup:
  • Download and install FileZilla
  • Open FileZilla β†’ File β†’ Site Manager
  • Create New Site β†’ Protocol: SFTP (SSH File Transfer Protocol)
  • Host: YOUR_SERVER_IP
  • Port: 22
  • Logon Type: Key File
  • User: ubuntu (or ec2-user for Amazon Linux)
  • Key File: Browse and select your fastapi-key.pem
  • Click "Connect"
πŸ“Œ WinSCP Setup:
  • Download and install WinSCP
  • Open WinSCP β†’ New Session
  • File Protocol: SFTP
  • Host name: YOUR_SERVER_IP
  • Port number: 22
  • User name: ubuntu
  • Private key file: Browse and select your fastapi-key.pem (WinSCP will convert it to .ppk)
  • Click "Login"
Option E: Using AWS S3 (For Large Files / Multiple Servers)
# Step 1: Upload to S3 from your local machine
aws s3 cp ./your-fastapi-project s3://your-bucket-name/your-fastapi-project --recursive

# Step 2: On EC2 server, download from S3
aws s3 cp s3://your-bucket-name/your-fastapi-project ./your-fastapi-project --recursive

# Step 3: If you don't have AWS CLI on EC2, install it:
sudo apt update
sudo apt install awscli -y
aws configure  # Add your access keys
Option F: Using Docker (Containerized Deployment)
🐳 Create a Dockerfile:
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
πŸ“€ Build and Push to Docker Hub:
# On your local machine:
docker build -t yourusername/fastapi-app:latest .
docker push yourusername/fastapi-app:latest

# On EC2 server:
docker pull yourusername/fastapi-app:latest
docker run -d -p 8000:8000 yourusername/fastapi-app:latest
Option G: Quick Transfer Using Python HTTP Server
# On YOUR LOCAL machine (where your code is):
cd your-fastapi-project
python3 -m http.server 8001

# On EC2 server (in a new terminal):
wget http://YOUR_LOCAL_IP:8001/main.py
wget http://YOUR_LOCAL_IP:8001/requirements.txt
# Download each file individually

# Note: Your local machine must be accessible from the internet
# (Use ngrok if behind NAT: https://ngrok.com/)
πŸ“Š Method Comparison
Method Best For Speed Ease of Use Version Control
Git Ongoing development, team collaboration ⭐⭐⭐⭐ ⭐⭐⭐⭐ βœ… Yes
SCP Single file transfer, quick uploads ⭐⭐⭐ ⭐⭐⭐⭐⭐ ❌ No
Rsync Large projects, incremental updates ⭐⭐⭐⭐⭐ ⭐⭐⭐ ❌ No
FileZilla/WinSCP GUI lovers, drag-and-drop ⭐⭐⭐ ⭐⭐⭐⭐⭐ ❌ No
AWS S3 Multiple servers, large files ⭐⭐⭐⭐ ⭐⭐⭐ ❌ No
Docker Containerized deployment, consistency ⭐⭐⭐⭐ ⭐⭐⭐ βœ… Yes
Pro Tip: For production deployments, use Git + CI/CD (GitHub Actions) or Docker for automatic deployment when you push code.
Important: Don't upload your .env file or any files containing secrets to GitHub! Add them to .gitignore.
Step 6: Set Up Python Virtual Environment & Install Dependencies
# 1. Create virtual environment (isolates your project dependencies)
cd ~/YOUR_PROJECT_NAME
python3 -m venv venv

# 2. Activate virtual environment
source venv/bin/activate

# Your prompt should now show (venv) at the beginning

# 3. Install your project dependencies
pip install -r requirements.txt

# 4. If you don't have requirements.txt, create it:
pip freeze > requirements.txt

# Or install common FastAPI packages directly:
pip install fastapi uvicorn sqlalchemy python-multipart

# 5. Verify installation
pip list  # Shows all installed packages

# 6. Test your application (temporary)
uvicorn main:app --host 0.0.0.0 --port 8000

# In your browser, visit: http://YOUR_SERVER_IP:8000
# You should see your API response!

# Press Ctrl+C to stop the test
Step 7: Configure Environment Variables (.env file)
# 1. Create .env file for production settings
nano .env

# 2. Add your configuration (modify as needed):
DATABASE_URL=sqlite:///./production.db
SECRET_KEY=your-super-secret-key-change-this
DEBUG=False
ALLOWED_HOSTS=YOUR_SERVER_IP,yourdomain.com

# 3. Save file: Ctrl+X, then Y, then Enter

# 4. Verify .env file is ignored by git (should be in .gitignore)
echo ".env" >> .gitignore

# 5. Test that your app reads environment variables
python3 -c "import os; from dotenv import load_dotenv; load_dotenv(); print(os.getenv('DEBUG'))"
Step 8: Create Systemd Service (Auto-start on reboot)

This ensures your app starts automatically when the server restarts.

# 1. Create service file
sudo nano /etc/systemd/system/fastapi-app.service

# 2. Paste this configuration (UPDATE paths to match your project):
[Unit]
Description=My FastAPI Application
After=network.target

[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/home/ubuntu/YOUR_PROJECT_NAME
Environment="PATH=/home/ubuntu/YOUR_PROJECT_NAME/venv/bin"
EnvironmentFile=/home/ubuntu/YOUR_PROJECT_NAME/.env
ExecStart=/home/ubuntu/YOUR_PROJECT_NAME/venv/bin/gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

# 3. Save file: Ctrl+X, then Y, then Enter

# 4. Reload systemd to recognize new service
sudo systemctl daemon-reload

# 5. Enable service to start on boot
sudo systemctl enable fastapi-app

# 6. Start the service now
sudo systemctl start fastapi-app

# 7. Check if it's running
sudo systemctl status fastapi-app

# You should see "active (running)" in green

# 8. View logs if needed
sudo journalctl -u fastapi-app -f
Step 9: Set Up Nginx as Reverse Proxy (RECOMMENDED)

Nginx handles web traffic efficiently and adds security.

# 1. Create Nginx configuration
sudo nano /etc/nginx/sites-available/fastapi-app

# 2. Paste this configuration:
server {
    listen 80;
    server_name YOUR_SERVER_IP;
    
    client_max_body_size 100M;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
    
    location /static {
        alias /home/ubuntu/YOUR_PROJECT_NAME/static;
        expires 30d;
    }
}

# 3. Save file: Ctrl+X, then Y, then Enter

# 4. Enable the site
sudo ln -s /etc/nginx/sites-available/fastapi-app /etc/nginx/sites-enabled/

# 5. Remove default site (optional)
sudo rm /etc/nginx/sites-enabled/default

# 6. Test Nginx configuration
sudo nginx -t

# 7. Restart Nginx
sudo systemctl restart nginx

# 8. Your app is now available at: http://YOUR_SERVER_IP (no :8000 needed!)
Step 10: Set Up SSL/HTTPS (Free with Let's Encrypt)

⚠️ You need a domain name for this step (e.g., yourdomain.com)

# 1. Install Certbot
sudo apt install -y certbot python3-certbot-nginx

# 2. Get SSL certificate (replace with your domain)
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# 3. Follow the prompts:
#    - Enter your email
#    - Agree to terms
#    - Choose redirect option (recommended)

# 4. Test auto-renewal
sudo certbot renew --dry-run

# 5. Your site is now available at: https://yourdomain.com

πŸ”§ Troubleshooting Common Issues

Solution:
  • Check Security Group: Ensure SSH (port 22) has your IP
  • Verify instance is running (not stopped)
  • Check you're using correct IP address
  • Try: ping YOUR_SERVER_IP
Solution:
  • Check service status: sudo systemctl status fastapi-app
  • Check Nginx: sudo systemctl status nginx
  • Verify Security Group has HTTP (80) and 8000 open
  • Check logs: sudo journalctl -u fastapi-app -f
Solution:
  • On Mac/Linux: chmod 400 fastapi-key.pem
  • Ensure you're using the correct username: ubuntu@
  • Verify key pair name matches
Solution:
  • Activate virtual env: source venv/bin/activate
  • Install missing package: pip install package_name
  • Update requirements.txt: pip freeze > requirements.txt
  • Check your main.py has proper app variable named "app"

πŸ“ Quick Reference - Daily Maintenance Commands

What to doCommand
View app statussudo systemctl status fastapi-app
Restart appsudo systemctl restart fastapi-app
Stop appsudo systemctl stop fastapi-app
View app logssudo journalctl -u fastapi-app -f
Restart Nginxsudo systemctl restart nginx
Update code from GitHubgit pull origin main && sudo systemctl restart fastapi-app
Install new Python packagesource venv/bin/activate && pip install package && sudo systemctl restart fastapi-app
View server resourceshtop (install: sudo apt install htop)
Check disk spacedf -h
Check memory usagefree -h

πŸ”„ Alternative AWS Deployment Methods

🐳 AWS ECS (Docker)

Best for containerized applications. Requires Docker knowledge.

# Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "main:app"]
πŸ“¦ AWS Elastic Beanstalk

Platform as a Service - AWS manages the infrastructure.

# Install EB CLI
pip install awsebcli

# Initialize and deploy
eb init -p python-3.11
eb create my-fastapi-env
eb deploy
⚑ AWS Lambda (Serverless)

Pay-per-request, auto-scaling to zero.

# Install Mangum
pip install mangum

# In main.py
from mangum import Mangum
handler = Mangum(app)
πŸ’‘ Cost Saving Tips for Free Tier
  • πŸ›‘ Stop instances when not in use - EC2 charges continue only for storage
  • πŸ—‘οΈ Delete unused EBS volumes - Old volumes cost money
  • πŸ“Έ Delete old AMIs and snapshots - They accumulate quickly
  • 🌐 Use CloudFront CDN - Free tier includes 1TB/month data transfer
  • πŸ“Š Set up billing alerts - Get notified before exceeding free tier
βœ… Deployment Checklist
  • ☐ EC2 instance running and accessible via SSH
  • ☐ Security group allows HTTP (80) and HTTPS (443)
  • ☐ Python virtual environment created and activated
  • ☐ All dependencies installed via pip
  • ☐ Environment variables configured (.env file)
  • ☐ Systemd service created and enabled
  • ☐ Nginx configured as reverse proxy
  • ☐ SSL certificate installed (if using domain)
  • ☐ Application accessible via browser
  • ☐ Logs checked for any errors

AWS Elastic Beanstalk Deployment (Simplified)

# Even easier than EC2 - AWS manages everything for you

# 1. Install EB CLI
pip install awsebcli

# 2. Initialize your project
cd your-fastapi-project
eb init -p python-3.11 my-fastapi-app --region us-east-1

# 3. Create environment and deploy
eb create my-fastapi-env --scale 1 --instance-type t2.micro

# 4. Open in browser
eb open

# 5. Update your code
git add .
git commit -m "update"
eb deploy

# 6. View logs
eb logs

AWS Lambda Serverless Deployment (Mangum)

# Perfect for APIs with variable traffic

# 1. Install Mangum
pip install mangum

# 2. Modify your main.py
from fastapi import FastAPI
from mangum import Mangum

app = FastAPI()

# Your routes here...

# Lambda handler
handler = Mangum(app)

# 3. Deploy using Serverless Framework
npm install -g serverless

# Create serverless.yml
service: fastapi-lambda

provider:
  name: aws
  runtime: python3.11
  region: us-east-1

functions:
  api:
    handler: main.handler
    events:
      - httpApi: '*'

# Deploy
serverless deploy
πŸŽ‰ Congratulations! Your FastAPI application is now live on AWS! Your users can access it at http://YOUR_SERVER_IP

17.2 Google Cloud Platform (GCP) Deployment

Google Cloud Run - Best for Containerized FastAPI Apps

Cloud Run is a fully managed serverless platform that automatically scales your containerized applications.

Prerequisites
  • Google Cloud account with billing enabled (free tier includes 2 million requests/month)
  • Google Cloud SDK installed
  • Docker installed locally
Deployment Steps
# Install and initialize Google Cloud SDK
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init

# Enable required services
gcloud services enable run.googleapis.com cloudbuild.googleapis.com

# Create Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
EOF

# Build and deploy
PROJECT_ID=$(gcloud config get-value project)
gcloud builds submit --tag gcr.io/$PROJECT_ID/eduhack-lab

# Deploy to Cloud Run
gcloud run deploy eduhack-lab \
    --image gcr.io/$PROJECT_ID/eduhack-lab \
    --platform managed \
    --region us-central1 \
    --allow-unauthenticated \
    --memory 512Mi \
    --cpu 1 \
    --min-instances 0 \
    --max-instances 10

Google Compute Engine (VM) Deployment

Similar to AWS EC2, GCE provides virtual machines with free tier eligibility (e2-micro instance).

# Create VM instance
gcloud compute instances create eduhack-vm \
    --zone=us-central1-a \
    --machine-type=e2-micro \
    --image-family=ubuntu-2204-lts \
    --image-project=ubuntu-os-cloud \
    --tags=http-server,https-server

# Create firewall rules
gcloud compute firewall-rules create allow-http --allow tcp:80 --source-ranges 0.0.0.0/0
gcloud compute firewall-rules create allow-https --allow tcp:443 --source-ranges 0.0.0.0/0

# SSH into VM
gcloud compute ssh eduhack-vm --zone=us-central1-a

# Follow same setup steps as AWS EC2

Cloud SQL (Managed PostgreSQL)

# Create PostgreSQL instance
gcloud sql instances create eduhack-db \
    --database-version=POSTGRES_15 \
    --tier=db-f1-micro \
    --region=us-central1 \
    --storage-size=10GB

# Set password
gcloud sql users set-password postgres --instance=eduhack-db --password=YourPassword123

# Create database
gcloud sql databases create eduhack --instance=eduhack-db

17.3 Microsoft Azure Deployment

Azure App Service - PaaS for FastAPI

Azure App Service provides a fully managed platform for hosting web applications with built-in scaling and load balancing.

Prerequisites
  • Azure account with free tier (F1 plan offers 1 hour/day free compute)
  • Azure CLI installed
Deployment Steps
# Login to Azure
az login

# Create resource group
az group create --name eduhack-rg --location eastus

# Create App Service plan (Linux)
az appservice plan create \
    --name eduhack-plan \
    --resource-group eduhack-rg \
    --sku F1 \
    --is-linux

# Create web app
az webapp create \
    --resource-group eduhack-rg \
    --plan eduhack-plan \
    --name eduhack-lab-app \
    --runtime "PYTHON:3.11"

# Configure startup command
az webapp config set \
    --resource-group eduhack-rg \
    --name eduhack-lab-app \
    --startup-file "gunicorn -w 2 -k uvicorn.workers.UvicornWorker app.main:app"

# Deploy from GitHub
az webapp deployment source config \
    --name eduhack-lab-app \
    --resource-group eduhack-rg \
    --repo-url https://github.com/yourusername/EduHack-Lab \
    --branch main \
    --manual-integration

# Set environment variables
az webapp config appsettings set \
    --resource-group eduhack-rg \
    --name eduhack-lab-app \
    --settings DATABASE_URL="sqlite:///./test.db" DEBUG="False"

Azure Container Instances

# Deploy container directly
az container create \
    --resource-group eduhack-rg \
    --name eduhack-container \
    --image yourdockerhub/eduhack-lab:latest \
    --dns-name-label eduhack-lab \
    --ports 8000 \
    --cpu 1 \
    --memory 1.5

17.4 DigitalOcean Deployment (Droplets & App Platform)

DigitalOcean Droplet - Simple VPS Hosting

DigitalOcean offers simple, predictable pricing starting at $4/month for basic droplets.

Quick Deployment with One-Click Apps
# Install doctl CLI
snap install doctl
doctl auth init

# Create droplet
doctl compute droplet create eduhack-droplet \
    --region nyc3 \
    --image ubuntu-22-04-x64 \
    --size s-1vcpu-1gb \
    --ssh-keys 

# SSH into droplet
ssh root@droplet-ip

# Use the same setup script as AWS EC2

DigitalOcean App Platform (PaaS)

# app.yaml
name: eduhack-lab
region: nyc
services:
  - name: api
    github:
      repo: yourusername/EduHack-Lab
      branch: main
    build_command: pip install -r requirements.txt
    run_command: gunicorn -w 2 -k uvicorn.workers.UvicornWorker app.main:app
    http_port: 8000
    instance_count: 1
    instance_size_slug: basic-xxs

# Deploy
doctl apps create --spec app.yaml

17.5 Heroku Deployment (Legacy & Alternatives)

⚠️ Note: Heroku discontinued free plans in November 2022. Use modern alternatives below.

Modern Heroku Alternatives

Railway.app - Best Free Tier Alternative
# Install Railway CLI
npm install -g @railway/cli

# Login and deploy
railway login
railway init
railway up

# Add PostgreSQL database
railway add -p postgresql
Render.com - Excellent Free Tier
# render.yaml
services:
  - type: web
    name: eduhack-lab
    runtime: python
    repo: https://github.com/yourusername/EduHack-Lab
    plan: free
    buildCommand: pip install -r requirements.txt
    startCommand: gunicorn app.main:app -w 2 -k uvicorn.workers.UvicornWorker
    envVars:
      - key: PYTHON_VERSION
        value: 3.11.0

databases:
  - name: eduhack-db
    databaseName: eduhack
    user: eduhack
    plan: free

17.6 Railway.app & Render.com Deployment

Railway.app Complete Setup

# Project structure for Railway
EduHack-Lab/
β”œβ”€β”€ app/
β”‚   └── main.py
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ runtime.txt (python-3.11.0)
└── railway.json

# railway.json
{
  "build": {
    "builder": "NIXPACKS"
  },
  "deploy": {
    "startCommand": "uvicorn app.main:app --host 0.0.0.0 --port 8000",
    "healthcheckPath": "/health"
  }
}

Render.com Complete Setup

# .render/Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "app.main:app", "-w", "2", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]

17.7 PythonAnywhere & Shared Hosting

❌ Not Recommended: PythonAnywhere doesn't support ASGI/WebSockets properly. Use VPS alternatives below.

Better Budget Alternatives (Under $5/month)

Hetzner Cloud - Best Performance for Price
# CX11 instance: €4.15/month
# 1 vCPU, 2GB RAM, 20GB SSD

# Quick deploy with Docker
curl -fsSL https://get.docker.com | sh
docker run -d -p 80:8000 yourusername/eduhack-lab:latest
Oracle Cloud Free Tier - Best Free Option
# Always free: 4 ARM cores, 24GB RAM, 200GB storage
# Create VM.Standard.A1.Fire instance
# Follow standard Ubuntu setup
Vultr Cloud Compute - Cheapest Option
# $2.50/month for IPv6-only
# $5/month for IPv4
# Use same setup as AWS EC2

17.8 VPS Deployment (Linode, Vultr, UpCloud)

Universal VPS Setup Script

#!/bin/bash
# deploy.sh - Run on fresh Ubuntu 22.04 VPS

set -e

echo "πŸš€ Starting EduHack-Lab deployment..."

# Update system
sudo apt update && sudo apt upgrade -y

# Install dependencies
sudo apt install -y python3-pip python3-venv nginx git

# Clone application
git clone https://github.com/yourusername/EduHack-Lab.git /var/www/eduhack
cd /var/www/eduhack

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

# Create .env file
cat > .env << EOF
DATABASE_URL=sqlite:///./test.db
SECRET_KEY=$(openssl rand -hex 32)
DEBUG=False
EOF

# Setup systemd service
sudo tee /etc/systemd/system/eduhack.service << 'EOF'
[Unit]
Description=EduHack-Lab FastAPI App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/eduhack
Environment="PATH=/var/www/eduhack/venv/bin"
ExecStart=/var/www/eduhack/venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# Setup Nginx
sudo tee /etc/nginx/sites-available/eduhack << 'EOF'
server {
    listen 80;
    server_name _;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

# Enable services
sudo systemctl daemon-reload
sudo systemctl enable eduhack
sudo systemctl start eduhack
sudo ln -s /etc/nginx/sites-available/eduhack /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx

echo "βœ… Deployment complete!"
echo "🌐 Visit: http://$(curl -s ifconfig.me)"

Linode Specific Setup

# Using Linode CLI
linode-cli linodes create \
    --label eduhack-lab \
    --region us-east \
    --type g6-nanode-1 \
    --image linode/ubuntu22.04 \
    --root_pass YourPassword123

17.9 Serverless Deployment (AWS Lambda + Mangum)

Complete Serverless Setup for FastAPI

Installation and Configuration
# Install required packages
pip install mangum

# Modify app/main.py
from fastapi import FastAPI
from mangum import Mangum

app = FastAPI(title="EduHack-Lab API")

@app.get("/")
async def root():
    return {"message": "Hello from Serverless FastAPI!"}

# Lambda handler
handler = Mangum(app)
Serverless Framework Configuration
# serverless.yml
service: eduhack-lab-serverless

provider:
  name: aws
  runtime: python3.11
  region: us-east-1
  memorySize: 512
  timeout: 30
  environment:
    DATABASE_URL: ${env:DATABASE_URL}

functions:
  api:
    handler: app.main.handler
    events:
      - httpApi:
          method: ANY
          path: /{proxy+}

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true
    layer: true

# Deploy
npm install -g serverless
serverless plugin install -n serverless-python-requirements
serverless deploy --stage production
Limitations and Considerations
  • ❌ Cold starts (5-10 seconds for Python)
  • ❌ 15-minute maximum execution time
  • ❌ 250MB deployment package limit
  • ❌ Limited WebSocket support
  • βœ… Pay-per-request (can be cheaper for low traffic)
  • βœ… Automatic scaling to zero

17.10 Kubernetes Deployment (EKS, GKE, AKS)

Complete Kubernetes Configuration

Deployment YAML
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: eduhack-lab
spec:
  replicas: 3
  selector:
    matchLabels:
      app: eduhack
  template:
    metadata:
      labels:
        app: eduhack
    spec:
      containers:
      - name: fastapi
        image: yourregistry/eduhack-lab:latest
        ports:
        - containerPort: 8000
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: DATABASE_URL
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
        readinessProbe:
          httpGet:
            path: /ready
            port: 8000
          initialDelaySeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: eduhack-service
spec:
  selector:
    app: eduhack
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: eduhack-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: eduhack-lab
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
Deploy Commands
# Apply configurations
kubectl apply -f deployment.yaml

# Check status
kubectl get pods
kubectl get services

# Get external IP
kubectl get service eduhack-service --watch

17.11 Platform Comparison & Cost Analysis

Cloud Platform Comparison Table

Platform Free Tier Starting Price Best For Difficulty
AWS EC2 750 hrs/month (12 months) $0.0116/hr (t4g.nano) Full control, complex apps Advanced
AWS Lambda 1M requests/month $0.20/1M requests Sporadic traffic, APIs Intermediate
Google Cloud Run 2M requests/month $0.10/100K requests Containerized apps Intermediate
Azure App Service 1 hour/day (F1 tier) $0.10/hr (B1 tier) .NET integration Intermediate
DigitalOcean $200 credit (60 days) $4/month Simple VPS needs Beginner
Railway.app $5 credit or 500 hrs $5/month Ease of use Beginner
Render.com 750 hrs/month $7/month Free SSL, easy deploy Beginner
Hetzner No free tier €4.15/month Budget VPS Intermediate

Cost Optimization Strategies

  • βœ… Use ARM instances (AWS Graviton, Hetzner ARM) - 20% cheaper
  • βœ… Right-size instances based on actual usage
  • βœ… Use spot/preemptible instances for non-critical workloads
  • βœ… Implement auto-scaling to reduce idle resources
  • βœ… Consider serverless for variable traffic patterns
  • βœ… Use CDN (CloudFront, Cloudflare) to reduce origin traffic

17.12 CI/CD Pipeline Setup for Each Platform

GitHub Actions for AWS EC2

# .github/workflows/deploy-aws.yml
name: Deploy to AWS EC2

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 /var/www/EduHack-Lab
            git pull origin main
            source venv/bin/activate
            pip install -r requirements.txt
            sudo systemctl restart eduhack

GitLab CI/CD for Any Platform

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

test:
  stage: test
  script:
    - pip install pytest
    - pytest tests/

build:
  stage: build
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

deploy:
  stage: deploy
  script:
    - ssh user@server "docker pull $DOCKER_IMAGE && docker-compose up -d"
  only:
    - main

17.13 Environment Variables & Secrets Management

Best Practices for Managing Secrets

Using AWS Secrets Manager
# Store secret
aws secretsmanager create-secret \
    --name eduhack-secrets \
    --secret-string '{"DATABASE_URL":"postgresql://...","SECRET_KEY":"..."}'

# Retrieve in code
import boto3
session = boto3.session.Session()
client = session.client('secretsmanager')
response = client.get_secret_value(SecretId='eduhack-secrets')
Using .env Files (Development Only)
# .env.example (commit to git)
DATABASE_URL=postgresql://user:password@localhost/db
SECRET_KEY=your-secret-key-here
DEBUG=True

# .env (never commit - add to .gitignore)
DATABASE_URL=postgresql://prod_user:prod_pass@prod-db/prod_db
SECRET_KEY=actual-production-secret-key
DEBUG=False
Using GitHub Secrets
# Store secrets in GitHub
# Settings β†’ Secrets and variables β†’ Actions

# Use in workflows
- name: Deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
    SECRET_KEY: ${{ secrets.SECRET_KEY }}
  run: python deploy.py

17.14 Database Hosting Options (RDS, Cloud SQL, Cosmos DB)

Managed Database Services Comparison

Provider Service Free Tier Starting Price
AWS RDS PostgreSQL 750 hrs/month (db.t3.micro) $0.017/hr
GCP Cloud SQL No free tier $0.015/hr (db-f1-micro)
Azure Cosmos DB 25 GB storage $0.008/hr
DigitalOcean Managed Database $15 credit $15/month
Connecting to Managed Databases
# AWS RDS Connection
DATABASE_URL=postgresql://username:password@database-1.xxxxxx.us-east-1.rds.amazonaws.com:5432/eduhack

# GCP Cloud SQL Connection
DATABASE_URL=postgresql://username:password@/eduhack?host=/cloudsql/INSTANCE_CONNECTION_NAME

# Azure Cosmos DB (PostgreSQL)
DATABASE_URL=postgresql://username:password@server.postgres.database.azure.com:5432/eduhack

17.15 Domain & SSL Configuration

Setting Up Custom Domain

DNS Configuration Examples
# A Record (for IP-based hosting)
Type: A
Name: @ or api
Value: 123.123.123.123 (your server IP)
TTL: 3600

# CNAME Record (for platform hosting)
Type: CNAME
Name: api
Value: your-app.railway.app or your-service.onrender.com
TTL: 3600
SSL with Let's Encrypt (Certbot)
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Get SSL certificate
sudo certbot --nginx -d api.yourdomain.com -d www.api.yourdomain.com

# Auto-renewal
sudo certbot renew --dry-run

# Manual renewal
sudo certbot renew
SSL for Cloud Platforms
# AWS (via Load Balancer or CloudFront)
# GCP (Managed SSL via Cloud Run)
gcloud run services update eduhack-lab --ingress=all

# Azure (Automatic SSL with App Service)
az webapp config ssl bind --certificate-thumbprint 

# DigitalOcean (App Platform auto SSL)
# Automatic with custom domain

17.16 Monitoring & Logging on Cloud Platforms

Setting Up Application Monitoring

AWS CloudWatch Setup
# Install CloudWatch agent
sudo wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i -E ./amazon-cloudwatch-agent.deb

# Configure CloudWatch agent
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

# Start CloudWatch agent
sudo systemctl start amazon-cloudwatch-agent
Structured Logging in FastAPI
# app/core/logging.py
import logging
import json
from datetime import datetime

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
            "function": record.funcName
        }
        return json.dumps(log_entry)

# Configure logger
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
Prometheus Metrics for FastAPI
# Install prometheus-fastapi-instrumentator
pip install prometheus-fastapi-instrumentator

# app/main.py
from prometheus_fastapi_instrumentator import Instrumentator

app = FastAPI()
Instrumentator().instrument(app).expose(app)

# Access metrics at: http://your-app/metrics

17.17 Auto-scaling & Load Balancing

Implementing Auto-scaling

AWS Auto Scaling Group
# Create launch template
aws ec2 create-launch-template \
    --launch-template-name eduhack-template \
    --image-id ami-0c55b159cbfafe1f0 \
    --instance-type t3.micro

# Create auto scaling group
aws autoscaling create-auto-scaling-group \
    --auto-scaling-group-name eduhack-asg \
    --launch-template LaunchTemplateName=eduhack-template \
    --min-size 2 \
    --max-size 5 \
    --desired-capacity 2 \
    --vpc-zone-identifier "subnet-xxx,subnet-yyy"

# Create scaling policy
aws autoscaling put-scaling-policy \
    --auto-scaling-group-name eduhack-asg \
    --policy-name cpu-scale-out \
    --policy-type TargetTrackingScaling \
    --target-tracking-configuration file://config.json
Load Balancer Configuration
# AWS Application Load Balancer
# 1. Create target group
# 2. Register EC2 instances
# 3. Create listener on port 80/443
# 4. Forward to target group

# Nginx as Load Balancer
upstream eduhack_backend {
    least_conn;
    server 10.0.1.1:8000;
    server 10.0.1.2:8000;
    server 10.0.1.3:8000;
}

server {
    listen 80;
    location / {
        proxy_pass http://eduhack_backend;
        proxy_set_header Host $host;
    }
}

17.18 Cost Optimization Strategies

Reduce Cloud Costs Without Sacrificing Performance

Compute Optimization
  • Use Spot/Preemptible Instances: Save 60-90% on non-critical workloads
  • Right-size Instances: Monitor CPU/memory usage and scale down
  • Use ARM Architecture: AWS Graviton, Hetzner ARM (20-30% cheaper)
  • Auto-scaling to Zero: Use serverless for development/staging environments
Storage Optimization
  • Use S3 Glacier for backups and logs
  • Delete unattached EBS volumes
  • Use EBS gp3 instead of gp2 (lower cost per GB)
  • Implement data lifecycle policies
Database Optimization
  • Use reserved instances for production databases
  • Implement read replicas only when needed
  • Use SQLite for development, managed DB for production
  • Clean up old database snapshots
Network Optimization
  • Use CloudFlare free tier as CDN
  • Implement caching to reduce origin traffic
  • Use internal load balancers instead of public
  • Monitor data transfer costs between regions

Free Tier Strategies for Learning

# Best free tier combination for learning:
1. AWS Free Tier: 750 hrs EC2 + RDS (12 months)
2. Google Cloud: 2 million requests on Cloud Run
3. Railway.app: $5 credit (good for testing)
4. Render.com: 750 hrs free web service
5. GitHub Actions: 2000 mins/month for CI/CD
6. CloudFlare: Free CDN + SSL + DDoS protection

# Multi-cloud strategy for maximum free tier:
- Frontend: Vercel/Netlify (free)
- Backend: Render.com (free tier)
- Database: Supabase (free PostgreSQL)
- Storage: CloudFlare R2 (10GB free)
- CI/CD: GitHub Actions (free)
πŸ’‘ Pro Tip: Use AWS Budget Alerts to avoid unexpected charges. Set up billing alerts at 50%, 75%, 90%, and 100% of your budget.

πŸŽ“ Module: Project Deployment Successfully Completed

You have successfully completed the deployment module of FastAPI Framework Development Course.

Your application is now ready for production deployment on any major cloud platform!

Important Interview Questions - FastAPI Framework

Comprehensive interview preparation guide covering 100+ frequently asked FastAPI questions for beginners, intermediate, and advanced developers. These questions are commonly asked in technical interviews for Python backend developer positions at companies like Microsoft, Amazon, Google, and startups.


Topic 1: FastAPI Fundamentals (10 Questions)

Q1. What is FastAPI and what makes it unique?

Answer: FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+.

  • High Performance: On par with Node.js and Go
  • Fast to Code: Increase development speed by 200-300%
  • Fewer Bugs: Reduce human-induced errors by about 40%
  • Intuitive: Great editor support with autocomplete
  • Standards-based: Based on OpenAPI and JSON Schema

Q2. Who created FastAPI and when?

Answer: SebastiΓ‘n RamΓ­rez created FastAPI in 2018. He was inspired by Flask, Django, and previous work on API frameworks.

Q3. What are the main features of FastAPI?

  • Automatic interactive API documentation (Swagger UI and ReDoc)
  • Data validation using Pydantic
  • Dependency injection system
  • Security and authentication built-in
  • WebSocket support
  • Background tasks
  • GraphQL support via additional libraries

Q4. What companies use FastAPI in production?

Answer: Microsoft (Azure services), Uber, Netflix, Discord, and thousands of startups use FastAPI for high-performance microservices.

Q5. What are the disadvantages of FastAPI?

  • Relatively new (less community resources than Django/Flask)
  • Async can be complex for beginners
  • Smaller ecosystem of third-party packages
  • May be overkill for simple APIs

Q6. How does FastAPI compare to Flask?

FeatureFastAPIFlask
Performance~70,000 req/sec~8,000 req/sec
Async SupportNativeLimited
Data ValidationBuilt-in (Pydantic)Third-party
API DocsAutomaticManual
Dependency InjectionBuilt-inManual

Q7. How does FastAPI compare to Django?

  • Django: Full-featured framework (ORM, admin, templates, auth) - better for monolithic applications
  • FastAPI: Microframework focused on APIs - better for microservices and high-performance APIs

Q8. What Python versions support FastAPI?

Answer: FastAPI requires Python 3.7+ and works with Python 3.8, 3.9, 3.10, 3.11, and 3.12.

Q9. What are the core libraries FastAPI is built on?

  • Starlette: For web routing and ASGI functionality
  • Pydantic: For data validation and serialization
  • Uvicorn: For ASGI server (production)

Q10. How do you install FastAPI?

pip install fastapi
pip install "uvicorn[standard]"  # ASGI server

# Or with all dependencies
pip install fastapi[all]

Topic 2: ASGI vs WSGI & Performance (8 Questions)

Q1. What is WSGI and what are its limitations?

Answer: WSGI (Web Server Gateway Interface) is a specification for synchronous Python web applications.

  • Limitations: Cannot handle WebSockets, long-polling, or HTTP/2
  • Concurrency: One request per worker at a time
  • Examples: Flask, Django (traditional), Pyramid

Q2. What is ASGI and how is it different from WSGI?

Answer: ASGI (Asynchronous Server Gateway Interface) is the spiritual successor to WSGI supporting async operations.

  • Supports: HTTP/1.1, HTTP/2, WebSockets, gRPC
  • Concurrency: Multiple requests per worker using async/await
  • Examples: FastAPI, Starlette, Django (ASGI mode)

Q3. Why does FastAPI use ASGI instead of WSGI?

  • Better performance with async I/O operations
  • WebSocket support for real-time features
  • HTTP/2 support for improved efficiency
  • Can handle thousands of concurrent connections

Q4. How does FastAPI achieve 70,000+ requests per second?

  • Starlette (high-performance ASGI framework)
  • Pydantic (Rust-based validation)
  • Uvicorn with uvloop (asyncio event loop)
  • Minimal overhead in request processing

Q5. What is Uvicorn and why is it recommended for FastAPI?

Answer: Uvicorn is a lightning-fast ASGI server implementation using uvloop and httptools.

# Run with Uvicorn
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

Q6. What is the difference between Uvicorn, Hypercorn, and Daphne?

ServerBest ForFeatures
UvicornFastAPI, StarletteFastest, HTTP/1.1, WebSocket
HypercornHTTP/2, HTTP/3HTTP/2, HTTP/3, Trio support
DaphneDjango ChannelsHTTP/1.1, WebSocket

Q7. How do you run FastAPI in production with Gunicorn?

# Install
pip install gunicorn uvicorn

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

# With custom options
gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

Q8. What is the request lifecycle in FastAPI?

  1. Client sends HTTP request
  2. ASGI server (Uvicorn) receives request
  3. Middleware stack processes request
  4. Route matching and parameter extraction
  5. Dependency injection resolution
  6. Path operation function execution
  7. Response validation and serialization
  8. Middleware processes response (reverse order)
  9. Response sent back to client

Topic 3: Dependency Injection & Pydantic (12 Questions)

Q1. What is Dependency Injection in FastAPI?

Answer: A design pattern where objects receive their dependencies from an external source rather than creating them internally.

from fastapi import Depends

def get_db():
    db = Database()
    try:
        yield db
    finally:
        db.close()

@app.get("/users")
def get_users(db = Depends(get_db)):
    return db.query()

Q2. What are the benefits of Dependency Injection?

  • Decoupling: Classes don't need to create dependencies
  • Testability: Easy to mock dependencies in tests
  • Reusability: Same dependency across multiple endpoints
  • Automatic documentation: Dependencies appear in OpenAPI docs

Q3. How do you create nested dependencies?

async def get_current_user(token: str = Depends(oauth2_scheme)):
    return verify_token(token)

async def get_current_active_user(
    current_user = Depends(get_current_user)
):
    if not current_user.is_active:
        raise HTTPException(status_code=400)
    return current_user

@app.get("/users/me")
async def get_me(user = Depends(get_current_active_user)):
    return user

Q4. What is the difference between Depends() and using regular parameters?

Answer: Depends() tells FastAPI to use the dependency injection system, allowing for caching, sub-dependencies, and better testability.

Q5. Can you use classes as dependencies?

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

@app.get("/items")
def get_items(params: CommonParams = Depends()):
    return {"q": params.q, "skip": params.skip}

Q6. What are Pydantic models?

Answer: Pydantic uses Python type hints for data validation and settings management.

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    email: str
    age: int = Field(ge=0, le=150)

Q7. How do you create custom validators in Pydantic?

from pydantic import BaseModel, validator

class User(BaseModel):
    name: str
    email: str
    
    @validator('email')
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('Invalid email')
        return v

Q8. What is the difference between Optional and default values?

from typing import Optional

class Item(BaseModel):
    name: str                    # Required
    description: str = None      # Optional with default None
    price: Optional[float] = None # Optional with default None
    tax: float = 0.0             # Optional with default 0.0

Q9. What is ORM mode in Pydantic?

Answer: ORM mode allows Pydantic to read data from ORM objects (like SQLAlchemy models).

class UserSchema(BaseModel):
    id: int
    name: str
    
    class Config:
        from_attributes = True  # orm_mode in older versions

Q10. How do you handle nested Pydantic models?

class Address(BaseModel):
    street: str
    city: str

class User(BaseModel):
    name: str
    address: Address  # Nested model

class UserList(BaseModel):
    users: List[User]  # List of models

Q11. What is Pydantic Settings?

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "My API"
    database_url: str
    secret_key: str
    
    class Config:
        env_file = ".env"

settings = Settings()

Q12. How does FastAPI use Pydantic for request/response validation?

  • Request body automatically validated against Pydantic model
  • Response automatically validated against response_model
  • Automatic 422 error responses for invalid data
  • OpenAPI schema generated from Pydantic models

Topic 4: Authentication & Security (10 Questions)

Q1. What authentication methods does FastAPI support?

  • OAuth2 with Password Flow (JWT tokens)
  • HTTP Basic Authentication
  • API Keys (header, query, or cookie)
  • Custom authentication schemes
  • OAuth2 with external providers (Google, GitHub)

Q2. How do you implement JWT authentication in FastAPI?

from jose import JWTError, jwt
from passlib.context import CryptContext

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def create_access_token(data: dict):
    return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

Q3. What is OAuth2PasswordBearer and how does it work?

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # Validate credentials and return token
    return {"access_token": token, "token_type": "bearer"}

@app.get("/users/me")
async def get_user(token: str = Depends(oauth2_scheme)):
    # Token automatically extracted from Authorization header
    return decode_token(token)

Q4. How do you implement Role-Based Access Control (RBAC)?

def get_current_user(token: str = Depends(oauth2_scheme)):
    user = decode_token(token)
    if not user:
        raise HTTPException(status_code=401)
    return user

def require_role(role: str):
    def role_checker(current_user = Depends(get_current_user)):
        if current_user.role != role:
            raise HTTPException(status_code=403)
        return current_user
    return role_checker

@app.get("/admin")
async def admin_only(user = Depends(require_role("admin"))):
    return {"message": "Admin access granted"}

Q5. How do you hash passwords securely?

from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Hash password
hashed = pwd_context.hash("mypassword")

# Verify password
is_valid = pwd_context.verify("mypassword", hashed)

Q6. How do you implement CORS in FastAPI?

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Q7. What are common security headers you should set?

  • Strict-Transport-Security (HSTS) - Force HTTPS
  • X-Frame-Options - Prevent clickjacking
  • X-Content-Type-Options - Prevent MIME sniffing
  • X-XSS-Protection - Cross-site scripting protection
  • Content-Security-Policy - Control resource loading

Q8. How do you implement rate limiting?

from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.get("/api")
@limiter.limit("5/minute")
async def api_endpoint(request: Request):
    return {"message": "Rate limited to 5 requests per minute"}

Q9. How do you protect against SQL injection?

  • Use ORM (SQLAlchemy) with parameterized queries
  • Never concatenate user input directly into SQL strings
  • Use Pydantic for input validation
  • Escape special characters when necessary

Q10. How do you implement API key authentication?

from fastapi.security import APIKeyHeader

api_key_header = APIKeyHeader(name="X-API-Key")

def verify_api_key(api_key: str = Depends(api_key_header)):
    if api_key not in valid_keys:
        raise HTTPException(status_code=403)
    return api_key

@app.get("/secure-data")
async def get_data(api_key: str = Depends(verify_api_key)):
    return {"data": "sensitive information"}

Topic 5: Async/Await & Concurrency (8 Questions)

Q1. What is the difference between synchronous and asynchronous code?

  • Synchronous: Code executes sequentially, blocking until each operation completes
  • Asynchronous: Code can run concurrently, non-blocking I/O operations

Q2. When should you use async/await in FastAPI?

  • βœ… Use async for: Database calls, API requests, file I/O, network operations
  • ❌ Don't use async for: CPU-intensive calculations, image processing, complex algorithms

Q3. How do you call async functions from sync code?

import asyncio

def sync_function():
    # Run async function synchronously
    result = asyncio.run(async_function())
    return result

Q4. How do you run blocking operations in async endpoints?

from fastapi.concurrency import run_in_threadpool

@app.get("/compute")
async def compute():
    # Run CPU-bound function in thread pool
    result = await run_in_threadpool(cpu_intensive_function, data)
    return result

Q5. What is the Global Interpreter Lock (GIL) and how does it affect async?

Answer: The GIL allows only one thread to execute Python bytecode at a time. Async/await helps with I/O concurrency, not CPU parallelism.

Q6. How do you run multiple async tasks concurrently?

async def fetch_data():
    # Run multiple API calls concurrently
    results = await asyncio.gather(
        fetch_user(),
        fetch_orders(),
        fetch_products()
    )
    return results

Q7. What is an event loop in asyncio?

Answer: The event loop manages and distributes the execution of different tasks, allowing for concurrent I/O operations.

Q8. Can you mix async and sync endpoints in FastAPI?

Answer: Yes, FastAPI handles both automatically. Sync endpoints run in a thread pool to avoid blocking the event loop.

@app.get("/async")
async def async_endpoint():
    await asyncio.sleep(1)
    return {"type": "async"}

@app.get("/sync")
def sync_endpoint():
    time.sleep(1)
    return {"type": "sync"}

Topic 6: Database Integration & SQLAlchemy (10 Questions)

Q1. How do you integrate SQLAlchemy with FastAPI?

# database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

SQLALCHEMY_DATABASE_URL = "postgresql://user:pass@localhost/db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

Q2. How do you handle database sessions properly?

Answer: Use dependency injection to create and close sessions automatically.

@app.get("/users")
def get_users(db: Session = Depends(get_db)):
    return db.query(User).all()
# Session automatically closed after request

Q3. How do you implement async database operations?

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

ASYNC_DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/db"
engine = create_async_engine(ASYNC_DATABASE_URL)

async def get_db():
    async with AsyncSession(engine) as session:
        yield session

@app.get("/users")
async def get_users(db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User))
    return result.scalars().all()

Q4. What is Alembic and how do you use it?

Answer: Alembic is a database migration tool for SQLAlchemy.

# Install
pip install alembic

# Initialize
alembic init alembic

# Create migration
alembic revision --autogenerate -m "create users table"

# Apply migration
alembic upgrade head

Q5. How do you handle the N+1 query problem?

  • Use joinedload() or selectinload() for eager loading
  • Use subqueryload() for complex relationships
  • Denormalize data when appropriate

Q6. What is the difference between lazy and eager loading?

  • Lazy Loading: Relationships loaded only when accessed (can cause N+1)
  • Eager Loading: Relationships loaded upfront in same query

Q7. How do you implement database transactions?

@app.post("/transfer")
def transfer_money(db: Session = Depends(get_db)):
    try:
        db.add(withdrawal)
        db.add(deposit)
        db.commit()  # Both operations succeed or fail together
    except Exception:
        db.rollback()  # Revert both operations
        raise

Q8. What is connection pooling and how do you configure it?

engine = create_engine(
    DATABASE_URL,
    pool_size=5,        # Number of connections to maintain
    max_overflow=10,    # Extra connections when needed
    pool_timeout=30,    # Time to wait for connection
    pool_recycle=1800   # Recycle connections after 30 minutes
)

Q9. How do you optimize database queries in FastAPI?

  • Add indexes on frequently queried columns
  • Use selectinload() for collections
  • Limit columns with with_entities()
  • Use pagination for large result sets
  • Implement query caching with Redis

Q10. How do you set up database migrations in production?

# Docker entrypoint script
#!/bin/bash
alembic upgrade head
uvicorn main:app --host 0.0.0.0 --port 8000

# Or as a separate job in CI/CD
alembic upgrade head

Topic 7: Routing, Middleware & WebSockets (10 Questions)

Q1. What are path and query parameters in FastAPI?

# Path parameters (required, part of URL)
@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

# Query parameters (optional, after ?)
@app.get("/search")
def search(q: str, page: int = 1, limit: int = 10):
    return {"query": q, "page": page}

Q2. How do you use APIRouter for modular routing?

# routers/users.py
router = APIRouter(prefix="/users", tags=["users"])

@router.get("/")
def get_users():
    return [{"name": "John"}]

# main.py
from routers import users
app.include_router(users.router)

Q3. How do you create custom middleware?

from starlette.middleware.base import BaseHTTPMiddleware

class CustomMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        # Before request
        start_time = time.time()
        
        response = await call_next(request)
        
        # After request
        response.headers["X-Process-Time"] = str(time.time() - start_time)
        return response

app.add_middleware(CustomMiddleware)

Q4. What is the difference between middleware and dependencies?

  • Middleware: Processes all requests globally, can modify request/response
  • Dependencies: Can be applied per endpoint, more granular control

Q5. How do you implement WebSocket endpoints?

@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Echo: {data}")
    except WebSocketDisconnect:
        print(f"Client {client_id} disconnected")

Q6. How do you handle WebSocket disconnections?

@app.websocket("/ws")
async def ws_endpoint(websocket: WebSocket):
    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            await manager.broadcast(data)
    except WebSocketDisconnect:
        manager.remove_client(websocket)

Q7. How do you set custom response headers?

from fastapi import Response

@app.get("/custom-header")
def get_data(response: Response):
    response.headers["X-Custom-Header"] = "Custom Value"
    return {"message": "Success"}

Q8. How do you return different response types?

from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse

@app.get("/html", response_class=HTMLResponse)
def get_html():
    return "

Hello World

" @app.get("/json") def get_json(): return {"message": "Hello"} # Auto-converted to JSON @app.get("/text", response_class=PlainTextResponse) def get_text(): return "Hello World"

Q9. How do you handle redirects?

from fastapi.responses import RedirectResponse

@app.get("/old-path")
def redirect():
    return RedirectResponse(url="/new-path", status_code=301)

Q10. How do you customize Swagger UI?

app = FastAPI(
    title="My API",
    description="API documentation",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
    openapi_url="/openapi.json"
)

Topic 8: Testing, Deployment & DevOps (12 Questions)

Q1. How do you test FastAPI applications?

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello World"}

Q2. How do you test endpoints that require authentication?

def test_protected_endpoint():
    # First get token
    token_response = client.post("/token", data={
        "username": "testuser",
        "password": "testpass"
    })
    token = token_response.json()["access_token"]
    
    # Use token
    response = client.get(
        "/protected",
        headers={"Authorization": f"Bearer {token}"}
    )
    assert response.status_code == 200

Q3. How do you test database operations?

@pytest.fixture
def db_session():
    engine = create_engine("sqlite:///:memory:")
    TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    Base.metadata.create_all(bind=engine)
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()

def test_create_user(db_session):
    user = User(name="Test")
    db_session.add(user)
    db_session.commit()
    assert user.id is not None

Q4. How do you run FastAPI in production?

# Using Gunicorn + Uvicorn (recommended)
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker

# Using Uvicorn directly
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

Q5. How do you Dockerize a FastAPI application?

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "main:app"]

Q6. How do you set up CI/CD for FastAPI?

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to server
        run: |
          ssh user@server "cd /app && git pull && docker-compose up -d --build"

Q7. How do you configure environment variables?

# .env file
DATABASE_URL=postgresql://localhost/db
SECRET_KEY=your-secret-key

# config.py
from pydantic_settings import BaseSettings

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

Q8. How do you set up logging in production?

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log'),
        logging.StreamHandler()
    ]
)

Q9. How do you monitor FastAPI applications?

  • Prometheus + Grafana: For metrics and visualization
  • ELK Stack: For log aggregation
  • Sentry: For error tracking
  • New Relic/DataDog: For APM monitoring

Q10. How do you implement health checks?

@app.get("/health")
async def health_check(db: Session = Depends(get_db)):
    # Check database
    db.execute("SELECT 1")
    
    # Check Redis
    redis_client.ping()
    
    return {
        "status": "healthy",
        "timestamp": datetime.now().isoformat()
    }

Q11. How do you scale FastAPI horizontally?

  • Run multiple Uvicorn workers on a single server
  • Use a load balancer (Nginx, AWS ALB) to distribute traffic
  • Deploy multiple instances behind a load balancer
  • Use container orchestration (Kubernetes, Docker Swarm)

Q12. What are common performance bottlenecks in FastAPI?

  • Synchronous database calls blocking the event loop
  • CPU-intensive operations in async endpoints
  • N+1 query problems
  • Missing database indexes
  • Large file uploads without streaming

Topic 9: Advanced Concepts & Best Practices (10 Questions)

Q1. What is OpenAPI and how does FastAPI use it?

Answer: OpenAPI is a specification for describing REST APIs. FastAPI automatically generates OpenAPI schema from your code.

Q2. How do you add custom metadata to OpenAPI?

app = FastAPI(
    title="My API",
    description="Custom description",
    version="2.0.0",
    terms_of_service="http://example.com/terms/",
    contact={
        "name": "API Support",
        "url": "http://example.com/support",
        "email": "support@example.com",
    },
    license_info={
        "name": "MIT",
        "url": "https://opensource.org/licenses/MIT",
    },
)

Q3. How do you implement background tasks?

from fastapi import BackgroundTasks

def send_email(email: str):
    # Time-consuming operation
    time.sleep(10)
    print(f"Email sent to {email}")

@app.post("/notify")
async def notify(email: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(send_email, email)
    return {"message": "Email will be sent in background"}

Q4. How do you handle file uploads?

from fastapi import File, UploadFile

@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    contents = await file.read()
    # Process file
    return {"filename": file.filename, "size": len(contents)}

Q5. How do you stream large files?

from fastapi.responses import StreamingResponse

@app.get("/large-file")
def get_large_file():
    def file_generator():
        with open("large-file.zip", "rb") as f:
            yield from f
    return StreamingResponse(file_generator(), media_type="application/zip")

Q6. How do you implement caching in FastAPI?

from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache

@app.get("/expensive")
@cache(expire=60)  # Cache for 60 seconds
async def expensive_operation():
    # Expensive computation
    return result

Q7. How do you version APIs in FastAPI?

# Option 1: URL versioning
app.include_router(v1_router, prefix="/api/v1")
app.include_router(v2_router, prefix="/api/v2")

# Option 2: Header versioning
@app.get("/users")
def get_users(version: str = Header("1.0")):
    if version == "2.0":
        return new_response
    return old_response

Q8. How do you implement GraphQL with FastAPI?

from strawberry.fastapi import GraphQLRouter
import strawberry

@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Hello World"

schema = strawberry.Schema(query=Query)
graphql_app = GraphQLRouter(schema)
app.include_router(graphql_app, prefix="/graphql")

Q9. What are FastAPI events (startup/shutdown)?

@app.on_event("startup")
async def startup_event():
    # Initialize database connections
    await database.connect()
    print("Application starting up")

@app.on_event("shutdown")
async def shutdown_event():
    # Clean up resources
    await database.disconnect()
    print("Application shutting down")

Q10. What are common security best practices in FastAPI?

  • Use HTTPS in production
  • Implement rate limiting
  • Validate all user inputs with Pydantic
  • Use environment variables for secrets
  • Implement proper authentication and authorization
  • Set secure HTTP headers (HSTS, CSP, X-Frame-Options)
  • Keep dependencies updated
  • Use parameterized queries to prevent SQL injection

Topic 10: Scenario-Based & Problem Solving (10 Questions)

Q1. How would you build a scalable e-commerce API with FastAPI?

  • Use APIRouter for modular organization (products, orders, users, carts)
  • Implement JWT authentication for users
  • Use PostgreSQL with SQLAlchemy for data persistence
  • Implement Redis caching for product catalog
  • Use Celery for order processing and email notifications
  • Implement rate limiting for API endpoints
  • Deploy with Docker and Kubernetes for scaling

Q2. How do you debug a slow endpoint in production?

  • Add timing middleware to log request duration
  • Check database query performance (N+1 problem)
  • Profile the endpoint using cProfile or py-spy
  • Check if sync code is blocking the event loop
  • Review database indexes and query plans
  • Check external API call latencies

Q3. How do you handle database migrations without downtime?

  • Use Alembic with backward-compatible migrations
  • Add columns as nullable first, backfill data, then make non-nullable
  • Use blue-green deployment strategy
  • Keep old API version until all clients migrate
  • Use feature flags to control rollout

Q4. How would you implement real-time notifications?

# Use WebSockets for real-time
@router.websocket("/ws/{user_id}")
async def websocket_endpoint(websocket: WebSocket, user_id: str):
    await manager.connect(user_id, websocket)
    try:
        while True:
            data = await websocket.receive_text()
            await manager.send_personal_message(f"Notification: {data}", user_id)
    except WebSocketDisconnect:
        manager.disconnect(user_id)

# Or use Server-Sent Events (SSE)
from sse_starlette.sse import EventSourceResponse

@app.get("/stream")
async def stream_notifications():
    async def event_generator():
        while True:
            yield {"data": "Notification"}
            await asyncio.sleep(1)
    return EventSourceResponse(event_generator())

Q5. How do you handle third-party API rate limits?

  • Implement request queuing with exponential backoff
  • Use circuit breaker pattern to stop requests when API is down
  • Cache responses when possible
  • Implement retry logic with jitter
  • Use message queue (RabbitMQ, Redis) for async processing

Q6. How would you implement search functionality?

@app.get("/search")
async def search(
    q: str,
    page: int = 1,
    limit: int = 20,
    sort: str = "relevance",
    filters: dict = None
):
    # Use PostgreSQL full-text search
    # Or integrate Elasticsearch
    # Or use vector search for semantic search
    results = await search_service.search(q, page, limit, sort, filters)
    return {"results": results, "total": len(results)}

Q7. How do you secure a FastAPI microservice?

  • Implement JWT or OAuth2 authentication
  • Use API gateway for external access
  • Implement mutual TLS for service-to-service auth
  • Validate all inputs and outputs
  • Use environment variables for secrets
  • Implement audit logging
  • Regular security updates and dependency scanning

Q8. How do you handle large dataset exports?

@app.get("/export")
async def export_data():
    def generate():
        # Stream results to avoid memory issues
        for batch in fetch_in_batches(1000):
            yield json.dumps(batch) + "\n"
    
    return StreamingResponse(
        generate(),
        media_type="application/x-ndjson",
        headers={"Content-Disposition": "attachment; filename=export.ndjson"}
    )

Q9. How do you implement A/B testing in FastAPI?

def ab_test_middleware(request: Request):
    user_id = request.headers.get("X-User-ID")
    variant = "A" if hash(user_id) % 2 == 0 else "B"
    request.state.variant = variant

@app.get("/feature")
async def test_feature(request: Request):
    variant = request.state.variant
    if variant == "A":
        return {"result": variant_a_logic()}
    return {"result": variant_b_logic()}

Q10. How do you troubleshoot memory leaks in FastAPI?

  • Use memory profiling tools (memory-profiler, tracemalloc)
  • Check for global variables accumulating data
  • Review database session management (ensure sessions are closed)
  • Check for circular references in dependencies
  • Monitor with Prometheus + Grafana
  • Use object counting to identify leaking types

πŸŽ“ Module: Important Interview Questions Successfully Completed

You have successfully completed 100+ interview questions covering all aspects of FastAPI development.

Practice these questions to ace your FastAPI developer interview!