FastAPI: Modern Python APIs

Create high-performance APIs with FastAPI, automatic documentation, and type hints. Complete guide to building modern Python web APIs with FastAPI framework.

18 min read
TechDevDex Team
5.0 Rating
FastAPI Modern Python APIs Guide

What You'll Master

FastAPI Fundamentals

Async programming, type hints, and automatic validation

Automatic Documentation

Interactive API docs with Swagger UI and ReDoc

Data Validation

Pydantic models for request/response validation

Authentication & Security

JWT, OAuth2, and dependency injection for security

Database Integration

SQLAlchemy, async database operations, and ORM

Testing & Deployment

Unit testing, async testing, and production deployment

Introduction to FastAPI

FastAPI is a modern, fast (high-performance) web framework for building APIs with Python 3.7+ based on standard Python type hints. It's designed to be easy to use and learn, fast to code, ready for production, and based on open standards.

Why Choose FastAPI?

FastAPI offers several advantages over traditional Python web frameworks:

  • High Performance: One of the fastest Python frameworks available
  • Automatic Documentation: Interactive API docs generated automatically
  • Type Safety: Full support for Python type hints
  • Easy to Use: Designed to be intuitive and easy to learn
  • Standards Based: Built on OpenAPI, JSON Schema, and OAuth2

Getting Started with FastAPI

FastAPI is built on top of Starlette for the web parts and Pydantic for the data parts. It provides automatic request validation, serialization, and documentation generation.

Installation and Basic Setup

python
# Install FastAPI and Uvicorn
pip install fastapi uvicorn

# Create a simple API
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

# Run the server
# uvicorn main:app --reload

Type Hints and Data Validation

FastAPI uses Python type hints to automatically validate request data and generate OpenAPI schemas. This provides excellent IDE support and runtime validation with minimal code.

Pydantic Models

python
from pydantic import BaseModel, EmailStr
from typing import Optional, List
from datetime import datetime

class UserBase(BaseModel):
    email: EmailStr
    full_name: str
    is_active: bool = True

class UserCreate(UserBase):
    password: str

class User(UserBase):
    id: int
    created_at: datetime
    
    class Config:
        orm_mode = True

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []

API Endpoints and HTTP Methods

FastAPI makes it easy to create RESTful APIs with proper HTTP methods, status codes, and response models. You can define complex endpoints with path parameters, query parameters, and request bodies.

CRUD Operations

python
from fastapi import FastAPI, HTTPException, Depends
from typing import List

app = FastAPI()

# In-memory storage (use database in production)
items = []

@app.post("/items/", response_model=Item)
async def create_item(item: Item):
    items.append(item)
    return item

@app.get("/items/", response_model=List[Item])
async def read_items(skip: int = 0, limit: int = 10):
    return items[skip: skip + limit]

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

@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: int, item: Item):
    if item_id >= len(items):
        raise HTTPException(status_code=404, detail="Item not found")
    items[item_id] = item
    return item

@app.delete("/items/{item_id}")
async def delete_item(item_id: int):
    if item_id >= len(items):
        raise HTTPException(status_code=404, detail="Item not found")
    del items[item_id]
    return {"message": "Item deleted"}

Authentication and Security

FastAPI provides built-in support for various authentication methods including OAuth2, JWT tokens, and API keys. You can use dependency injection to handle authentication across your application.

JWT Authentication

python
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

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

def get_password_hash(password):
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    return username

Database Integration

FastAPI works well with various databases through SQLAlchemy, databases, and other ORMs. You can use both synchronous and asynchronous database operations depending on your needs.

SQLAlchemy Integration

python
from sqlalchemy import Column, Integer, String, DateTime, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from fastapi import Depends

SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)
    hashed_password = Column(String)
    created_at = Column(DateTime)

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

@app.post("/users/", response_model=User)
async def create_user(user: UserCreate, db: Session = Depends(get_db)):
    db_user = User(email=user.email, hashed_password=get_password_hash(user.password))
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

Testing FastAPI Applications

FastAPI provides excellent testing support through the TestClient, which allows you to test your API endpoints without running a server. You can write comprehensive unit and integration tests.

Writing Tests

python
from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

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

def test_create_item():
    item_data = {
        "name": "Test Item",
        "description": "A test item",
        "price": 9.99,
        "tax": 1.0,
        "tags": ["test", "example"]
    }
    response = client.post("/items/", json=item_data)
    assert response.status_code == 200
    data = response.json()
    assert data["name"] == item_data["name"]
    assert data["price"] == item_data["price"]

def test_read_item():
    response = client.get("/items/0")
    assert response.status_code == 200
    data = response.json()
    assert "name" in data
    assert "price" in data

Deployment and Production

FastAPI applications can be deployed using various methods including Docker, cloud platforms, and traditional servers. Use ASGI servers like Uvicorn or Gunicorn for production deployment.

Docker Configuration

dockerfile
# Dockerfile
FROM python:3.9-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"]

# requirements.txt
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.0
sqlalchemy==2.0.23

Best Practices

  • Type Hints: Use comprehensive type hints for better IDE support
  • Error Handling: Implement proper exception handling and custom exceptions
  • Documentation: Leverage automatic documentation generation
  • Testing: Write comprehensive tests for all endpoints
  • Security: Implement proper authentication and authorization
  • Performance: Use async/await for I/O operations

Conclusion

FastAPI is an excellent choice for building modern Python APIs. Its combination of high performance, automatic documentation, type safety, and ease of use makes it ideal for both small projects and large-scale applications. With its growing ecosystem and community support, FastAPI is becoming the go-to framework for Python API development.