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 |
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:
- Register coroutines with event loop
- When await is encountered, control returns to event loop
- Event loop handles other tasks while waiting
- When I/O completes, coroutine resumes
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 |
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
1.5 FastAPI Request Lifecycle
Understanding how FastAPI processes a request is crucial for debugging and optimization:
Complete Request Flow:
- Client Request β HTTP request sent to server
- ASGI Server (Uvicorn) β Receives request, creates ASGI scope
- ASGI Application (FastAPI) β Receives scope, receive, send
- Middleware Stack (TopβBottom) β Each middleware processes request
- Route Matching β FastAPI matches path to path operation
- Dependency Resolution β All dependencies resolved (may include sub-dependencies)
- Parameter Extraction β Extract path, query, body, headers
- Validation β Validate data against Pydantic models
- Path Operation Function β Execute endpoint logic
- Response Preparation β Convert return value to response
- Response Validation β Validate response against response_model
- Middleware Stack (BottomβTop) β Each middleware processes response
- ASGI Response β Send response back to client
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
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
}
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
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
π 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 β