fastapi-large-app-template icon indicating copy to clipboard operation
fastapi-large-app-template copied to clipboard

🚀 Production-Grade FastAPI Template • JWT Auth • Rate Limiting • Alembic Migrations • Async PostgreSQL (connection pooling) • Async Redis (efficient pooling) • Gunicorn + Uvicorn • Docker • Async Rea...

FastAPI Large Application Template 🚀

FastAPI PostgreSQL Redis

A production-ready FastAPI template designed for building secure, scalable APIs with modern best practices baked in. This template provides a robust foundation for enterprise-grade applications, featuring essential security measures, performance optimizations, and maintainable architecture patterns out of the box.

Features ✨

  • JWT Authentication with refresh tokens 🔒
  • Custom Rate Limiting per user/service ⏱️
  • Unified Logging (UVICORN + GUNICORN) 📝
  • Redis Connection Pooling (Async) with fail-open strategy 🧠
  • PostgreSQL Connection Pooling (Async) with health checks 🐘
  • Standardized API Responses 📦
  • Alembic for Database Migrations 🗄️
  • Modern Package Management with uv
  • Production-Ready Error Handling 🛡️
  • Docker + Gunicorn + Uvicorn Stack 🐳⚡

Tech Stack 🛠️

Component Technology
Framework FastAPI 0.111+
Database PostgreSQL 14+
Cache Redis 6+
ORM SQLAlchemy 2.0
Migrations Alembic
Authentication JWT (OAuth2 Password Bearer)
Rate Limiting Redis-backed Custom Implementation
Package Manager uv (fast Python installer)
Containerization Docker

Project Structure 🌳

.
├── app
│   ├── alembic
│   │   ├── versions
│   │   ├── README
│   │   ├── env.py
│   │   └── script.py.mako
│   ├── core
│   │   ├── __init__.py
│   │   ├── database.py
│   │   ├── logging_config.py
│   │   └── settings.py
│   ├── health
│   │   └── health_router.py
│   ├── todo
│   │   ├── todo_crud.py
│   │   ├── todo_model.py
│   │   ├── todo_router.py
│   │   ├── todo_schema.py
│   │   └── todo_service.py
│   ├── user
│   │   ├── user_auth.py
│   │   ├── user_crud.py
│   │   ├── user_model.py
│   │   ├── user_router.py
│   │   ├── user_schema.py
│   │   └── user_service.py
│   ├── utils
│   │   ├── auth_dependency.py
│   │   ├── helper.py
│   │   └── rate_limiter.py
│   ├── alembic.ini
│   └── main.py
├── docs
│   └── swagger-screenshot.png
├── tests
│   ├── __init__.py
│   └── test_health.py
├── CONTRIBUTORS.txt
├── Dockerfile
├── LICENSE
├── README.md
├── gunicorn_config.py
├── pyproject.toml
├── run.sh
└── tree.txt

11 directories, 35 files

Key Implementations 🔑

Database Pooling Configuration

PostgreSQL (SQLAlchemy 2.0 + asyncpg):

from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

# Async PostgreSQL connection pool
engine = create_async_engine(
    "postgresql+asyncpg://user:pass@host:port/dbname",
    pool_size=20,          # Persistent connection pool size
    max_overflow=10,       # Temporary connections beyond pool_size
    pool_recycle=300,      # Recycle connections every 300s
    pool_pre_ping=True,    # Validate connections before use
    future=True            # Enable SQLAlchemy 2.0 behavior
)

# Async session factory configuration
AsyncSessionLocal = async_sessionmaker(
    bind=engine,
    expire_on_commit=False,  # Prevent attribute expiration on commit
    autoflush=False,         # Manual flush control
    class_=AsyncSession      # Use SQLAlchemy's async session class
)

Key Features:

  • 🚀 Full Async Support: Non-blocking database operations via asyncpg
  • 🔄 Connection Recycling: Prevents stale connections in long-running applications
  • 🩺 Connection Validation: Pre-ping checks verify connection health
  • 📈 Optimized Pooling: Balances memory usage and concurrent requests
  • SQLAlchemy 2.0: Future-proof API with explicit transaction control

Redis Connection Pool:

redis = await Redis(
    host="redis.prod.internal",
    port=6379,
    db=0,
    password="securepassword",
    socket_connect_timeout=5,    # 5s connection timeout
    socket_keepalive=True,       # Maintain TCP keepalive
    retry_on_timeout=True,       # Auto-retry failed operations
    max_connections=100,         # Max pool size
    health_check_interval=30     # Validate connections every 30s
)
  • Enterprise Features: TLS support, cluster mode ready
  • Resiliency: Automatic retries and health checks

🔒 Secure Endpoint Example

Protected Todo Creation:

@router.post("/")
async def create_todo(
    body: TodoCreate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """
    Implements:
    - JWT Authentication
    - User-based Rate Limiting
    - Structured Error Handling
    - Audit Logging
    """
    try:
        # Rate limit check
        await user_rate_limiter(current_user.user_id, "todo_write")

        # Business logic
        data = await create_todo_service(current_user.user_id, body, db)

        # Standardized success response
        return {
            "status": "success",
            "message": "Todo created",
            "data": data
        }

    except HTTPException as e:
        # Preserve existing HTTP exceptions
        raise
    except Exception as e:
        # Log full error context
        logger.error(f"Todo creation failed: {str(e)}", exc_info=True)
        # Return standardized error format
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Internal server error"
        )

⏱️ Custom Rate Limiting

Implementation:

async def user_rate_limiter(
    user_id: str,
    service: str,
    times: int = 5,
    seconds: int = 60
):
    """
    Redis-backed rate limiter using LUA scripts for atomic operations
    """
    key = f"rl:user:{user_id}:{service}"
    try:
        pexpire = await FastAPILimiter.redis.evalsha(
            FastAPILimiter.lua_sha, 1,
            key,
            str(times),
            str(seconds * 1000)  # Convert to milliseconds
        )
        if pexpire != 0:
            raise HTTPException(
                status_code=429,
                detail=f"Try again in {ceil(pexpire/1000)} seconds"
            )
    except Exception as e:
        logger.error(f"Rate limit check failed: {str(e)}")
        # Fail-open during Redis outages

Features: ✅ User+service specific limits ✅ Atomic Redis operations via LUA scripts ✅ Fail-open circuit breaker pattern ✅ Millisecond precision timeouts ✅ Automatic retry-after calculation


📝 Unified Logging System

Configuration:

logging_config = {
    "version": 1,
    "formatters": {
        "standard": {
            "format": "[{asctime}] [{process}] [{levelname}] {module}.{funcName}:{lineno} - {message}",
            "datefmt": "%Y-%m-%d %H:%M:%S %z",
            "style": "{"
        }
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "standard",
            "stream": "ext://sys.stdout"
        }
    },
    "loggers": {
        "": {"level": "DEBUG", "handlers": ["console"], "propagate": False},
        "uvicorn": {"level": "INFO", "propagate": False},
        "uvicorn.access": {"level": "INFO", "propagate": False},
        "uvicorn.error": {"level": "INFO", "propagate": False}
    }
}

Log Example:

[2024-05-20 14:30:45 +0000] [1234] [INFO] todo.routers.create_todo:52 - Created todo ID:42

Features: 📌 Consistent timestamp with timezone 📌 Process ID tracking 📌 Module/function/line number context 📌 Uvicorn log unification 📌 Production-ready INFO level defaults


📦 Standardized API Response

Success Response:

{
  "status": "success",
  "message": "Todo created successfully",
  "data": {
    "id": 42,
    "task": "Implement rate limiting"
  }
}

Error Response:

{
  "status": "error",
  "message": "Validation Failed",
  "errors": [
    {
      "field": "task",
      "message": "Field required"
    }
  ]
}

Implementation:

@app.exception_handler(RequestValidationError)
async def validation_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=422,
        content={
            "status": "error",
            "code": 422,
            "message": "Validation Failed",
            "errors": exc.errors()
        }
    )

@app.exception_handler(HTTPException)
async def http_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "status": "error",
            "code": exc.status_code,
            "message": exc.detail,
            "errors": getattr(exc, "errors", None)
        }
    )

Features: ✅ RFC-compliant error formats ✅ Automatic validation error parsing ✅ Consistent error code mapping ✅ Detailed error context preservation

Getting Started

Prerequisites

  • Python 3.11+
  • PostgreSQL 14+
  • Redis 6+
  • Docker (optional)

Installation

git clone https://github.com/akhil2308/fastapi-large-app-template.git
cd fastapi-large-app-template

# Install uv (if not already installed)
pip install uv

# Sync dependencies and create virtual environment
# This installs all packages defined in pyproject.toml
uv sync --all-extras

# Install Git Hooks
# This ensures code quality checks run automatically on commit
uv run pre-commit install

Configuration

Set environment variables

cp .env.example .env
# Fill in DB, Redis, JWT, and other values

Alembic Commands (Migrations)

Generate new migration:

uv run alembic -c app/alembic.ini revision --autogenerate -m "message"

Apply migrations:

uv run alembic -c app/alembic.ini upgrade head

Running

Development:

uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

Production:

./run.sh  # Starts Gunicorn with Uvicorn workers

Code Standards & Quality 🛡️

This project enforces code quality using Ruff (linter/formatter) and Mypy (static type checker).

Manual Checks

1. Linting & Formatting (Ruff)

# See what code Ruff wants to fix (Dry Run)
uv run ruff check .

# Actually fix the code (Auto-formatting & Import sorting)
uv run ruff check . --fix
uv run ruff format .

2. Static Type Checking (Mypy)

# Check for type errors
uv run mypy .

Note: 🔒 A pre-commit hook is configured. When you attempt to git commit, these checks will automatically run to ensure no bad code is pushed to the repository.

---

## API Documentation 📚

Access interactive docs after starting server:
- **Swagger UI:** `http://localhost:8000/docs`
- **ReDoc:** `http://localhost:8000/redoc`
- **OpenAPI:** `http://localhost:8000/openapi.json`

## Contributing

See [CONTRIBUTORS.txt](CONTRIBUTORS.txt) for contribution guidelines and code of conduct.

## License

This project is licensed under the MIT License - see [LICENSE](LICENSE) for details.