Skip to content

hybridinteract/fastapi-template

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FastAPI Backend Template

A production-ready, reusable FastAPI backend template with:

  • ⚑ FastAPI + SQLAlchemy 2.0 async ORM
  • πŸ” JWT auth with refresh tokens and RBAC (Role-Based Access Control)
  • πŸ—„οΈ PostgreSQL (asyncpg) + Redis (caching + Celery broker)
  • βš™οΈ Celery background tasks with Flower monitoring
  • πŸ“¦ Object storage abstraction (DigitalOcean Spaces / S3-compatible)
  • πŸ”„ Alembic async migrations
  • πŸ“Š Prometheus metrics via /metrics
  • πŸͺ΅ Rotating file + colored console logging
  • 🐳 Docker Compose ready (multi-stage Dockerfile)
  • πŸ““ Activity log (append-only audit trail)
  • πŸ—’οΈ Release notes (What's New system)

πŸš€ Quick Start

1. Setup Environment

cp .env.example .env
# Edit .env β€” at minimum set:
#   APP_NAME, POSTGRES_*, SECRET_KEY, JWT_SECRET_KEY

2. Install Dependencies

pip install uv
uv pip install -r pyproject.toml

3. Start Infrastructure (Docker)

docker-compose up -d postgres redis

4. Run Migrations

alembic upgrade head

5. Seed Database (roles + permissions)

python -m app.user.seed

Note: Seeding also runs automatically at startup. It is idempotent.

6. Create Super Admin

python -m app.user.create_admin

7. Start Application

# Development (with hot reload)
uvicorn app.core.main:app --reload

# With Docker (all services)
docker-compose up -d

8. Access API

URL Description
http://localhost:8000/docs Swagger UI
http://localhost:8000/redoc ReDoc
http://localhost:8000/health Health check
http://localhost:8000/metrics Prometheus metrics
http://localhost:5555 Flower (Celery monitoring)

🐳 Docker

# Start all services
docker-compose up -d

# View API logs
docker-compose logs -f api

# Stop all services
docker-compose down

# Stop and remove volumes (WARNING: destroys data)
docker-compose down -v

Services

Service Port Description
api 8000 FastAPI application
postgres 5432 PostgreSQL database
redis 6379 Redis (cache + Celery broker)
celery_worker β€” Background task worker
flower 5555 Celery task monitoring UI

⚑ Celery (Background Tasks)

# Start worker locally (without Docker)
celery -A app.core.background.celery_app:celery_app worker --loglevel=info

# Flower monitoring locally
celery -A app.core.background.celery_app:celery_app flower --port=5555

πŸ“ Project Structure

app/
β”œβ”€β”€ core/                    # Shared infrastructure (never project-specific)
β”‚   β”œβ”€β”€ main.py              # FastAPI app factory + lifespan
β”‚   β”œβ”€β”€ settings.py          # Pydantic Settings (env-based config)
β”‚   β”œβ”€β”€ database.py          # Async SQLAlchemy engine + session
β”‚   β”œβ”€β”€ models.py            # DeclarativeBase for all models
β”‚   β”œβ”€β”€ crud.py              # Generic CRUDBase[Model, Create, Update]
β”‚   β”œβ”€β”€ exceptions.py        # Global exception handlers
β”‚   β”œβ”€β”€ middleware.py        # CORS, GZip, TrustedHost, timing
β”‚   β”œβ”€β”€ logging.py           # Rotating + colored console logging
β”‚   β”œβ”€β”€ metrics.py           # Prometheus instrumentator
β”‚   β”œβ”€β”€ utils.py             # utc_now() and shared helpers
β”‚   β”œβ”€β”€ alembic_models_import.py  # Single place to register all models
β”‚   β”œβ”€β”€ background/          # Celery app + task infrastructure
β”‚   β”œβ”€β”€ cache/               # Redis cache abstraction
β”‚   └── object_storage/      # S3-compatible file storage
β”‚
β”œβ”€β”€ apis/
β”‚   └── v1.py                # Aggregates all module routers
β”‚
β”œβ”€β”€ user/                    # Auth + RBAC module
β”‚   β”œβ”€β”€ models.py            # User, Role, Permission, RefreshToken
β”‚   β”œβ”€β”€ seed.py              # Idempotent role/permission seeder ← edit this
β”‚   β”œβ”€β”€ create_admin.py      # Interactive super-admin creation CLI
β”‚   β”œβ”€β”€ auth_management/     # JWT login, refresh, logout
β”‚   β”œβ”€β”€ permission_management/  # RBAC scoped access helpers
β”‚   β”œβ”€β”€ crud/                # CRUD for users, roles, permissions, tokens
β”‚   β”œβ”€β”€ schemas/             # Pydantic schemas
β”‚   β”œβ”€β”€ services/            # Business logic
β”‚   └── routes/              # FastAPI routers
β”‚
β”œβ”€β”€ activity/                # Append-only audit log module
β”œβ”€β”€ release_notes/           # "What's New" release notes module
β”‚
└── <your_module>/           # Add new feature modules here
    β”œβ”€β”€ models/              # SQLAlchemy models
    β”œβ”€β”€ schemas/             # Pydantic schemas
    β”œβ”€β”€ crud/                # CRUD operations
    β”œβ”€β”€ services/            # Business logic
    β”œβ”€β”€ routes/              # FastAPI routers
    β”œβ”€β”€ dependencies.py      # FastAPI Depends() helpers
    β”œβ”€β”€ exceptions.py        # Module-specific exceptions
    β”œβ”€β”€ enums.py             # Module enums
    └── permissions.py       # Permission constants

migrations/                  # Alembic migration files
docker/                      # Dockerfile + entrypoint scripts

πŸ›οΈ Engineering Conventions

Full standards: engineering.hybridinteractive.in/standards/project-structure

This project follows the Hybrid Interactive Engineering Standards β€” a Modular Monolith architecture based on Domain-Driven Design (DDD). Files are grouped by feature/domain (e.g., user/, product/), not by technical concern (not all models in one folder, all routes in another).


1. Architectural Philosophy

Principle What It Means Here
Separation of Concerns HTTP routing, business logic, and database access are strictly decoupled into independent layers
Dependency Injection Use FastAPI Depends() to pass sessions, user context, and config β€” never import them directly in routes
Async First All I/O operations (DB, HTTP, file) must use async/await
Strict Typing All inputs/outputs use Pydantic schemas with explicit validation β€” no raw dict returns

2. Feature Module Structure

Every domain feature lives in its own vertical slice:

app/<feature_name>/
β”œβ”€β”€ __init__.py          # Module public API β€” exports only what consumers need
β”œβ”€β”€ models/              # ORM entity classes defining database tables
β”œβ”€β”€ schemas/             # Pydantic models for request validation & response shaping
β”œβ”€β”€ crud/                # Repository layer β€” exclusively DB interactions
β”œβ”€β”€ services/            # Business logic β€” orchestrates crud, cache, external calls
β”œβ”€β”€ routes/              # FastAPI routers β€” HTTP interface only
β”œβ”€β”€ dependencies.py      # Feature-specific FastAPI Depends() providers
β”œβ”€β”€ enums.py             # Feature-level enums and constants
β”œβ”€β”€ exceptions.py        # Domain-specific error classes
β”œβ”€β”€ tasks.py             # Celery background tasks (if applicable)
└── tests/               # Unit and integration tests for this feature

3. Layer Responsibilities & Strict Rules

A. Route Layer (routes/)

  • Purpose: Parse HTTP inputs β†’ call service β†’ return HTTP response
  • ❌ NO business logic β€” no loops, conditionals, or rule validations
  • ❌ NO direct DB queries β€” never import or call session.execute() directly
  • βœ… Rely entirely on Depends() for services and DB session
  • βœ… Catch domain exceptions raised by services and map them to HTTP status codes
# βœ… Correct route
@router.post("/leads", response_model=LeadResponse)
async def create_lead(
    data: LeadCreate,
    session: AsyncSession = Depends(get_session),
    current_user: User = Depends(get_current_active_user),
    _: None = Depends(require_permission("leads:create")),
):
    return await lead_service.create(session, data, created_by=current_user)

B. Service Layer (services/)

  • Purpose: Execute business rules, coordinate between crud/cache/external systems
  • βœ… Owns transaction boundaries β€” only services call session.commit() or session.rollback()
  • ❌ Must be completely agnostic to HTTP β€” no Request or Response objects here
  • βœ… Interacts with the DB exclusively through the module's crud/ instances
# βœ… Correct service β€” owns commit
async def create(self, session: AsyncSession, data: LeadCreate, created_by: User) -> Lead:
    lead = await lead_crud.create(session, obj_in=data)
    await session.commit()   # ← service owns this, always
    return lead

C. Data Access Layer (crud/)

  • Purpose: Encapsulate SQL queries behind clean Python interfaces
  • βœ… Inherit from app/core/crud.py's CRUDBase wherever possible
  • ❌ NEVER call session.commit() β€” only session.add() and session.flush()
  • βœ… Methods are purely data-centric β€” no business conditions or rules
# βœ… Correct CRUD β€” flush only, no commit
async def create(self, session: AsyncSession, *, obj_in: LeadCreate) -> Lead:
    db_obj = Lead(**obj_in.model_dump())
    session.add(db_obj)
    await session.flush()       # ← get DB-generated ID, never commit
    await session.refresh(db_obj)
    return db_obj

D. Schema Layer (schemas/)

  • Purpose: Define structured request/response validation
  • βœ… Split by intent: LeadCreate, LeadUpdate, LeadResponse β€” separate classes
  • βœ… Enforce validation rules (string lengths, regex, value bounds) at schema level
  • ❌ Never return raw ORM objects from routes β€” always use a Response schema

4. Implementing a New Feature β€” Execution Order

Follow this exact sequence (from the engineering standard):

1. schemas/   β†’ Define request, update, and response Pydantic models
2. models/    β†’ Define the SQLAlchemy ORM model and run migration
3. crud/      β†’ Implement data access methods (extend CRUDBase)
4. services/  β†’ Write business logic, call crud, commit transactions
5. routes/    β†’ Expose HTTP endpoints, inject dependencies, use schemas
6. tests/     β†’ Write tests covering the new behavior

5. Error Handling Rules

  • ❌ Never raise a raw HTTPException(status_code=500) from inside services or CRUD
  • βœ… Define domain exceptions in the module's exceptions.py:
# app/product/exceptions.py
from fastapi import HTTPException, status

class ProductNotFoundException(HTTPException):
    def __init__(self, product_id: str):
        super().__init__(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Product '{product_id}' not found"
        )
  • βœ… Global exception handlers in app/core/exceptions.py translate unhandled exceptions to safe HTTP responses
  • βœ… Routes may catch domain exceptions and re-raise or return appropriate responses

6. Adding a New Feature Module β€” Checklist

β–‘ 1. Create app/<feature>/ with the standard sub-structure
β–‘ 2. Define schemas first  β†’  app/<feature>/schemas/
β–‘ 3. Add ORM model        β†’  app/<feature>/models/
β–‘ 4. Register model       β†’  app/core/alembic_models_import.py
β–‘ 5. Run migration        β†’  alembic revision --autogenerate -m "<description>"
β–‘ 6. Apply migration      β†’  alembic upgrade head
β–‘ 7. Implement CRUD       β†’  app/<feature>/crud/  (extend CRUDBase)
β–‘ 8. Implement service    β†’  app/<feature>/services/
β–‘ 9. Add permissions      β†’  app/user/seed.py  (PERMISSIONS + ROLE_PERMISSIONS)
β–‘ 10. Define routes       β†’  app/<feature>/routes/
β–‘ 11. Register router     β†’  app/apis/v1.py
β–‘ 12. Write tests         β†’  app/<feature>/tests/

See docs/PROJECT_CONVENTIONS.md for the full in-depth guide.


πŸ“ Authentication Endpoints

Method Endpoint Description
POST /api/v1/auth/register Register user
POST /api/v1/auth/login Login (returns access + refresh tokens)
POST /api/v1/auth/refresh Refresh access token
POST /api/v1/auth/logout Logout (revoke refresh token)
GET /api/v1/auth/me Get current user
PUT /api/v1/auth/me Update profile

βš™οΈ Configuration Reference

All configuration is via environment variables (.env file). Key variables:

Variable Required Description
APP_NAME No Application name (default: MyApp)
POSTGRES_USER Yes Database username
POSTGRES_PASSWORD Yes Database password
POSTGRES_DB Yes Database name
SECRET_KEY Yes Min 32 chars β€” for signing
JWT_SECRET_KEY Yes Min 32 chars β€” for JWT tokens
REDIS_HOST No Redis host (default: localhost)
ENVIRONMENT No development/staging/production

See .env.example for the full list.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages