Skip to content

binlecode/example-todo-fastapi-async-db

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FastAPI Async Todo App

A modern FastAPI application demonstrating async database operations with SQLAlchemy 2.0 and SQLite.

πŸš€ Features

  • Async/Await: Full async support with FastAPI and SQLAlchemy 2.0
  • Modern SQLAlchemy: Using async_sessionmaker and create_async_engine
  • Auto-generated API Docs: Interactive OpenAPI/Swagger documentation
  • Clean Architecture: Separated concerns with models, schemas, and routers
  • Database Migrations: Automatic table creation and seeding
  • Type Safety: Full type hints and Pydantic validation

πŸ“‹ Quick Start

Prerequisites

  • Python 3.11+
  • Virtual environment (recommended)

Installation

# Set Python version
pyenv shell 3.11

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

# Install dependencies
pip install -r requirements.txt

# Optional: upgrade to latest versions
pip install --upgrade $(pip freeze | cut -d '=' -f 1)

Running the Application

# Start with database reset and seed data
RESET_DB=true uvicorn app.main:app --reload

# Start without resetting database
uvicorn app.main:app --reload

Access API Documentation

Open your browser to: http://127.0.0.1:8000/docs

🐳 Run with Docker

You can run this FastAPI app in a container using Docker. This is the recommended way for consistent deployment and local development.

Build the Docker Image

docker build -t fastapi-todo-app-async .

Run the Container

docker run --rm -p 8000:8000 \
  -e RESET_DB=true \
  --name fastapi-todo-app-async \
  fastapi-todo-app-async

This will start the app and expose it at http://localhost:8000.

Development Tips

  • Mount your code for live reload (optional):
    docker run --rm -p 8000:8000 \
      -v $(pwd)/app:/app/app \
      -e RESET_DB=true \
      fastapi-todo-app
  • Use environment variables to control database reset and configuration.
  • For production, remove RESET_DB=true and consider using a production-ready server like Gunicorn with Uvicorn workers.

TODO: Docker Compose with external database support

πŸ—οΈ Architecture Overview

Tech Stack

  • FastAPI 0.115.2 - Modern async web framework
  • SQLAlchemy 2.0.36 - Async ORM with latest patterns
  • SQLite - File-based database with async support via aiosqlite
  • Pydantic - Data validation and serialization
  • Passlib - Password hashing with bcrypt

Project Structure

app/
β”œβ”€β”€ main.py              # FastAPI app initialization
β”œβ”€β”€ db.py                # Async database configuration
β”œβ”€β”€ db_migration.py      # Database initialization and seeding
β”œβ”€β”€ models.py            # SQLAlchemy ORM models
β”œβ”€β”€ schemas.py           # Pydantic validation schemas
β”œβ”€β”€ crud_todo.py         # Todo CRUD operations
β”œβ”€β”€ crud_user.py         # User CRUD operations
β”œβ”€β”€ security.py          # Password hashing utilities
└── routers/
    β”œβ”€β”€ users.py         # User API endpoints
    └── todos.py         # Todo API endpoints

πŸ”§ Database Configuration

Async Engine Setup

The application uses SQLAlchemy 2.0 async patterns with:

  • create_async_engine() with connection pooling
  • async_sessionmaker() for session factory
  • Connection lifecycle management
  • Automatic cleanup on shutdown

Database URL

SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sqlite.db"

Session Management

Two approaches supported:

  1. Dependency Injection (FastAPI routers):
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
    async with AsyncSessionLocal() as session:
        yield session
  1. Explicit Context Manager:
async with AsyncSessionLocal() as session:
    # Your database operations
    await session.commit()

πŸ“Š API Endpoints

Users

  • GET /api/users/ - List all users (with optional filtering)
  • GET /api/users/{user_id} - Get user by ID
  • POST /api/users/ - Create new user
  • PUT /api/users/{user_id} - Update user
  • DELETE /api/users/{user_id} - Delete user

Todos

  • GET /api/todos/ - List all todos
  • GET /api/todos/{todo_id} - Get todo by ID
  • POST /api/todos/ - Create new todo
  • PUT /api/todos/{todo_id} - Update todo
  • DELETE /api/todos/{todo_id} - Delete todo

πŸ” Advanced Features

Dynamic Filtering

The application supports dynamic query filtering using SQLAlchemy 2.0 syntax. Filters are built using ColumnElement expressions.

Eager Loading

Two eager loading strategies implemented:

  • joinedload: Uses JOIN queries for one-to-many relationships
  • selectinload: Uses separate SELECT queries for many-to-one relationships

Relationship Management

  • Users have many Todos (one-to-many)
  • Automatic cascade deletes
  • UUID primary keys for better compatibility

πŸ§ͺ Development

Environment Setup

# Manual dependency installation (if needed)
pip install sqlalchemy[asyncio] aiosqlite fastapi uvicorn pydantic[email] passlib[bcrypt]

Database Drivers

For different databases:

  • PostgreSQL: pip install asyncpg
  • MySQL: pip install asyncmy
  • SQLite: pip install aiosqlite (already included)

Configuration

Set environment variables as needed:

export RESET_DB=true  # Reset database on startup
export SQLALCHEMY_DATABASE_URL="postgresql+asyncpg://user:pass@localhost/dbname"

πŸ“š Key Concepts

Async Patterns

  • All database operations use async/await
  • Proper session lifecycle management
  • Connection pooling for optimal performance
  • Graceful shutdown with connection cleanup

Security

  • Password hashing with bcrypt
  • Email validation with Pydantic
  • Input validation and sanitization
  • No sensitive data in logs

Type Safety

  • Full type hints throughout codebase
  • Pydantic models for validation
  • SQLAlchemy 2.0 type-safe queries
  • MyPy compatible

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published