FastAPI Framework
Introduction to FastAPI
FastAPI is a modern, fast (high-performance) web framework for building APIs with Python 3.6+ based on standard Python type hints. It's designed to be easy to use, fast to code, and ready for production.
Key Features:
- Fast: Very high performance, on par with NodeJS and Go
- Fast to code: Increase the speed of development by 200% to 300%
- Automatic API documentation
- Based on Python type hints
- Modern Python features (async/await)
- Automatic data validation
Why FastAPI?
FastAPI combines the best of modern Python features with automatic API documentation and validation, making it ideal for building robust, high-performance APIs.
Installation and Setup
Basic Setup
# Create virtual environment
python -m venv venv
# Activate virtual environment
# Windows:
venv\Scripts\activate
# Unix/MacOS:
source venv/bin/activate
# Install FastAPI and Uvicorn
pip install fastapi uvicorn
# Basic FastAPI application
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# Run with: uvicorn main:app --reload
Project Structure
myapi/
├── app/
│ ├── __init__.py
│ ├── main.py
│ ├── dependencies.py
│ ├── routers/
│ ├── models/
│ └── schemas/
├── tests/
├── alembic/
├── requirements.txt
└── README.md
Core Concepts
Pydantic Models
from pydantic import BaseModel
from typing import Optional
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
tax: Optional[float] = None
Request and Response Models
@app.post("/items/", response_model=Item)
async def create_item(item: Item):
return item
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: int):
return {"name": "Example", "price": 10.5}
Path Operations
Basic Routing
from fastapi import Path, Query
@app.get("/items/{item_id}")
async def read_item(
item_id: int = Path(..., title="The ID of the item"),
q: str = Query(None, max_length=50)
):
return {"item_id": item_id, "q": q}
Request Bodies
from fastapi import Body
@app.post("/items/{item_id}")
async def update_item(
item_id: int,
item: Item,
user: User,
importance: int = Body(...)
):
results = {"item_id": item_id, "item": item}
return results
Data Validation
Field Validation
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
price: float = Field(..., gt=0)
description: Optional[str] = Field(None, max_length=1000)
tags: List[str] = Field(default_factory=list)
Custom Validators
from pydantic import validator
class User(BaseModel):
username: str
password: str
password2: str
@validator('password2')
def passwords_match(cls, v, values):
if 'password' in values and v != values['password']:
raise ValueError('passwords do not match')
return v
Database Integration
SQLAlchemy Setup
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()
Database Models
from sqlalchemy import Column, Integer, String
class DBItem(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
description = Column(String)
price = Column(Float)
Authentication and Security
OAuth2 with JWT
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=401,
detail="Could not validate credentials"
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
return username
except JWTError:
raise credentials_exception
Protected Routes
@app.get("/users/me")
async def read_users_me(
current_user: User = Depends(get_current_user)
):
return current_user
Deployment
Production Setup
Deployment Checklist:
- Use Uvicorn with Gunicorn
- Configure CORS
- Set up proper logging
- Enable HTTPS
- Use environment variables
# Gunicorn configuration
# gunicorn.conf.py
workers_per_core = 1
cores = multiprocessing.cpu_count()
default_web_concurrency = workers_per_core * cores
# CORS setup
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)