Skip to content

ixdlabs/fastapi-template

Repository files navigation

πŸš€ FastAPI Template

A robust, production-ready FastAPI backend with structured tooling, OpenTelemetry, Celery, and more.

🧬 Cloning the Repository

git clone https://github.com/ixdlabs/fastapi-template

βš™οΈ Environment Setup

Requires Python 3.14+ and uv. uv manages the environment - no venv activation needed.

Install Dependencies

This project uses a uv.lock file for consistent dependency installation.

uv sync

Configure Environment Variables

Copy .env.example to .env (create one if missing) and adjust values as needed.

🧹 Code Formatting & Linting

This project uses pre-commit hooks with ruff and pyright strict mode.

# Install pre-commit hooks
uv run pre-commit install
# Run formatting and type checks
uv run pre-commit --all-files

βœ… Running Tests

Run the test suite (pytest):

uv run pytest

πŸ—„οΈ Database Configuration

SQLite is the default for development and will create sqlite.db automatically. No additional setup is required to start the API.

For development, PostgreSQL is strongly recommended. Using a different database engine may lead to issues when generating migrations.

To switch to PostgreSQL, set:

DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/dbname

Alembic Migrations

Run migrations after changing models or switching databases:

# Apply migrations
uv run alembic upgrade head
# Create new migration
uv run alembic revision --autogenerate -m "describe change"
# Downgrade one migration
uv run alembix downgrade -1

πŸ“ˆ Observability with OpenTelemetry

This application uses OpenTelemetry (OTel) to export traces, metrics, and logs via OTLP. SigNoz is the recommended backend, but any OTLP-compatible collector will work.

Environment Configuration

Add the following variables to .env file:

# Set false (default) to disable otel
OTEL_ENABLED=true

# Resource settings to uniquely identify the service
OTEL_RESOURCE_SERVICE_NAME=backend
OTEL_RESOURCE_ENVIRONMENT=development

# Only OTEL_EXPORTER_OTLP_ENDPOINT is required for self-hosted SigNoz
OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
OTEL_EXPORTER_OTLP_INSECURE=false
OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"

Running the Application with OTel Enabled

Do not use autoreload when running with OpenTelemetry instrumentation.

Start the application using:

uv run uvicorn app.web_app:app

Installing OTel Instrumentations

To discover recommended instrumentations for the environment, run:

uv run opentelemetry-bootstrap

This command lists optional packages (e.g., FastAPI, SQLAlchemy, HTTP clients) that can be instrumented. Select only the ones that is used directly in the application.

Install only the instrumentations that are needed:

uv add --group=opentelemetry <package>
# Example:
# uv add --group=opentelemetry opentelemetry-instrumentation-fastapi
# uv add --group=opentelemetry opentelemetry-instrumentation-sqlalchemy

The instrumentations should be configured inside the app/core/otel.py.

Once configured, traces, metrics, and logs are automatically exported via OTLP and data appears in SigNoz (or your chosen backend).

⚑ FastAPI Server

Run after applying migrations:

uv run fastapi dev app/web_app.py

Docs available at: http://127.0.0.1:8000/api/docs

🧰 Included Packages

  • FastAPI for the web framework and dependency injection.
  • SQLAlchemy async with Alembic for migrations.
  • Pydantic for request/response models and settings management.
  • PyJWT for JWT authentication.
  • Celery for background tasks.
  • pytest for unit testing.

🎯 Background Tasks with Celery

Celery is configured for async task execution.

Local Development (Eager Mode)

Run tasks without a worker:

CELERY_TASK_ALWAYS_EAGER=true

Without Eager Mode

Default queue backend is SQLite. Run following commands to start the worker and the beat scheduler.

# Worker - do the actual work
uv run celery -A app.worker_app worker
# Beat Scheduler - schedule periodic tasks
uv run celery -A app.worker_app beat

🐳 Docker Setup

Build & run the production image:

docker build -t fastapi-template .
docker run --rm -p 8000:8000 --env-file .env fastapi-template

For persistent storage, use a volume or PostgreSQL via DATABASE_URL.

You can apply migrations in the container before first run if you use an external DB:

docker run --rm --env-file .env fastapi-template uv run alembic upgrade head

🧾 Project Structure

app/
β”œβ”€ core/                            # Global configuration & shared infrastructure
β”‚  β”œβ”€ emails/                       # Email templates & base components
β”‚  β”œβ”€ tests/                        # Core-level tests
β”‚  └─ <module_1>.py
β”‚
β”œβ”€ features/                        # Feature-based modules (vertical slices)
β”‚  β”œβ”€ <domain_1>/                   # Example feature/domain
β”‚  β”‚  β”œβ”€ models/                    # Database models
β”‚  β”‚  β”‚  β”œβ”€ tests/                  # Model tests
β”‚  β”‚  β”‚  └─ <model_1>.py
β”‚  β”‚  β”‚
β”‚  β”‚  β”œβ”€ services/                  # Business logic & API handlers
β”‚  β”‚  β”‚  β”œβ”€ common/                 # Endpoints shared across user types
β”‚  β”‚  β”‚  β”œβ”€ <user_type>/            # User-type–specific endpoints
β”‚  β”‚  β”‚  └─ tasks/                  # Async/worker services
β”‚  β”‚  β”‚     β”œβ”€ tests/               # Task tests
β”‚  β”‚  β”‚     └─ <do_action>.py       # **Single-responsibility task
β”‚  β”‚  β”‚
β”‚  β”‚  β”œβ”€ api.py                     # Feature-level API router
β”‚  β”‚  └─ tasks.py                   # Feature-level Celery task registry
β”‚  β”‚
β”‚  β”œβ”€ api.py                        # Aggregate feature routers
β”‚  β”œβ”€ tasks.py                      # Aggregate feature tasks
β”‚  └─ models.py                     # Aggregate feature models
β”‚
β”œβ”€ fixtures/                        # Test factories & fixtures
β”‚  └─ <model_1_factory>.py
β”‚
β”œβ”€ migrations/                      # Alembic migration root
β”‚  β”œβ”€ versions/                     # Migration files
β”‚  β”‚  └─ <datetime>_<id>_<slug>.py
β”‚  β”œβ”€ env.py                        # Alembic runtime configuration
β”‚  └─ script.mako                   # Migration template
β”‚
β”œβ”€ conftest.py                      # Pytest global configuration
β”œβ”€ fastapi.py                       # FastAPI app factory / wiring
β”œβ”€ web_app.py                       # Web application entry point
β”œβ”€ celery.py                        # Celery app factory / wiring
β”œβ”€ worker_app.py                    # Worker entry point
β”‚
β”œβ”€ pyproject.toml                   # Project metadata & dependencies
└─ uv.lock                          # Dependency lockfile

The single responsibility task should have below structure.

# ... imports

logger = logging.getLogger(__name__)

router = APIRouter()          # ... for API endpoints
registry = TaskRegistry()     # ... for worker tasks


# Input/Output
# -----------------------------------------------------------------------------


class DoActionInput(BaseModel):
  ...


class DoActionOutput(BaseModel):
  ...


# Exceptions
# -----------------------------------------------------------------------------


class Example1Exception(ServiceException):
    status_code = status.HTTP_404_NOT_FOUND
    type = "<domain>/<user-type>/<do-action>/example-exception-1"
    detail = "Example exception 1 message"


# Action
# -----------------------------------------------------------------------------


# ... for API endpoints
@raises(Example1Exception)
@router.post("/do-action")
async def do_action(form: DoActionInput, dep1: Example1Dep, ...) -> DoActionOutput:
    """
    Documentation for the action with any special notes.
    """


# ... for worker tasks
@registry.background_task("do_action")
async def do_action(task_input: DoActionInput, dep1: Example1WorkerDep, ...) -> DoActionOutput:
    """
    Documentation for the action with any special notes.
    """


DoActionTaskDep = Annotated[BackgroundTask, Depends(do_action)]

# ... for service methods
async def do_action(form: DoActionInput, dep1: Example1Dep, ...) -> DoActionOutput:
    """
    Documentation for the action with any special notes.
    """

The single responsibility task denoting a worker task should have below structure.

🧠 VS Code Config

{
  "python.testing.pytestArgs": ["app"],
  "python.testing.unittestEnabled": false,
  "python.testing.pytestEnabled": true,
  "editor.rulers": [120]
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages