Skip to content

kemalcalak/Fastapi-Template

Repository files navigation

⚑ FastAPI Layered Architecture Template

A modern, production-ready FastAPI template utilizing a clean, layered (hexagonal-style) architecture. This template is designed for building robust and scalable backend services with clear separation of concerns, easy testing, and high maintainability.

πŸ’‘ Why This Template?

While FastAPI is incredibly fast and flexible, it doesn't enforce a specific project structure. As projects grow, they often turn into a tangled mess of tightly coupled route handlers, business logic, and database calls. This template provides Enterprise-Grade Readiness from minute zero.

  • Pre-Configured Tooling: uv, pytest, ruff, and alembic are pre-integrated. No wrestling with environment setups.
  • Scalable Architecture: Extends beyond simple MVC. It isolates API routing, business logic (Services), and database interactions (Repositories) making the app highly testable and maintainable.
  • Production-Ready Security & Observability: JWT authentication, HttpOnly cookies for refresh tokens, token blacklisting, password hashing, and rate limiting are baked in. Out-of-the-box integration with Sentry for robust error monitoring.
  • Consistent Responses: Global exception handlers utilizing centralized success and error messages prevent hardcoded strings and standardize the API response structures.
  • Docker First: A docker-compose.yaml is ready to spin up your backend, PostgreSQL database, and Redis instances instantly.

πŸ”— Frontend Compatibility

This backend template is designed to seamlessly integrate with the companion Next.js 16 + React 19 + TypeScript Enterprise Template. You can find the frontend template here: kemalcalak/NextJS-Template.

The two templates share the same auth contract: HttpOnly access_token / refresh_token cookies, /api/v1 prefix, X-Requested-With CSRF header, and a uniform { success, data, message, error } response envelope.


πŸš€ Features & Tech Stack

This template integrates the best-in-class Python ecosystem tools to provide a seamless developer experience:

  • Framework: FastAPI for building APIs with Python 3.12+ based on standard Python type hints.
  • Architecture: Strict Layered Architecture separating routers, services, repositories, use cases, and models, fully utilizing FastAPI's dependency injection.
  • Database & ORM: SQLAlchemy 2.0 with asyncpg for non-blocking operations, and Alembic for schema migrations.
  • Observability & Error Tracking: Sentry built-in integration for tracking unhandled exceptions and performance tracing.
  • Caching: Redis integration using redis.asyncio for robust, high-performance distributed caching.
  • Validation & Config: Pydantic v2 and pydantic-settings for robust data validation and environment management.
  • Security & Auth: JWT access/refresh tokens accepted via either HttpOnly cookies or Authorization: Bearer, bcrypt password hashing, Redis-backed token blacklist (logout invalidation), strict origin-check middleware (returns 404 for foreign origins), and Slowapi rate limiting for brute-force protection.
  • Account Lifecycle: Email verification, password reset, password change, and soft-delete with grace period β€” accounts marked for deletion can be reactivated until the cron worker purges them.
  • Background Jobs: arq worker (separate container in compose) runs cron jobs such as delete_expired_accounts at the configured time.
  • Audit Trail: user_activity table records auth events and CRUD actions with IP / user agent. The audit_unexpected_failure decorator captures unexpected route failures.
  • Smart Email Validation & Delivery: Built-in asynchronous email sending with SMTP, domain MX record checking using dnspython, and auto-updating disposable email provider filtering via Redis cache.
  • Standardized API Responses: Global exception handlers standardizing success/error schemas, utilizing a centralized messages module (app/core/messages/) to prevent hardcoded responses.
  • First Superuser Seed: On startup, an initial admin is created from FIRST_SUPERUSER / FIRST_SUPERUSER_PASSWORD if none exists.
  • Tooling: uv for blazing-fast package management, and Ruff for linting and formatting.
  • Testing: Comprehensive async testing setup with pytest and pytest-asyncio, in-memory SQLite via aiosqlite, fakeredis, and autouse SMTP/MX patches β€” tests never hit Postgres or the network.

βœ… CI/CD Ready

The repository structure supports standard Continuous Integration pipelines out-of-the-box. Ensure you configure your CI (GitHub Actions, GitLab CI, etc.) to run:

  1. Dependency Install: uv sync
  2. Linting: uv run ruff check .
  3. Formatting Check: uv run ruff format --check .
  4. Unit & Integration Tests: uv run pytest

πŸ“¦ Setup & Local Development

Prerequisites

  • Python >= 3.12
  • Docker & Docker Compose (for local database and Redis)
  • uv package manager (recommended)

1. Clone the Repository

Clone the repository to your local machine:

git clone https://github.com/kemalcalak/fastapi-template.git
cd fastapi-template

2. Environment Variables

Create a .env file from the provided template:

cp .env.example .env

Your .env file should look like this, filled with your actual configuration:

# Application Settings
PROJECT_NAME="FastAPI Template"
SECRET_KEY="changethis"
ENVIRONMENT="local"
FIRST_SUPERUSER="admin@example.com"
FIRST_SUPERUSER_PASSWORD="changethis"
FRONTEND_HOST="http://localhost:5173"

# Database Settings
POSTGRES_SERVER="localhost"
POSTGRES_PORT=5432
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="changethis"
POSTGRES_DB="app"

# Redis Cache Settings
REDIS_URL="redis://localhost:6379/0"

# Email / SMTP Settings (Optional)
SMTP_HOST="smtp.example.com"
SMTP_PORT=465
SMTP_USE_STARTTLS=True
SMTP_USE_SSL=False
SMTP_USER="smtp_username"
SMTP_PASSWORD="smtp_password"
EMAILS_FROM_EMAIL="noreply@example.com"

# Sentry (only initialized when ENVIRONMENT != "local")
SENTRY_DSN=

3. Start the Application via Docker

This project provides a docker-compose.yaml to spin up the entire stack, including the backend service, a local PostgreSQL instance, a Redis container, and the arq background worker:

docker-compose up -d --build

The API will be available at http://localhost:8000. You can test the endpoints via the Swagger UI available at http://localhost:8000/docs.

To run the worker manually (e.g. when developing the API on the host):

uv run arq app.worker.settings.WorkerSettings

4. Run Migrations

To generate and apply the database tables using Alembic, run the migration command inside the backend container:

# Apply existing migrations
docker-compose exec backend uv run alembic upgrade head

If you modify models in app/models/ and need to generate a new migration script:

docker-compose exec backend uv run alembic revision --autogenerate -m "description_of_changes"
docker-compose exec backend uv run alembic upgrade head

πŸ› οΈ Testing & Code Quality

Testing

Tests are written using pytest and configured for async execution with pytest-asyncio. Configuration details can be found in pytest.ini.

To run the test suite locally:

uv run pytest

Code Quality

This project uses Ruff for both code linting and formatting. The configurations are specified in pyproject.toml.

  • Check for issues: uv run ruff check .
  • Format code: uv run ruff format .
  • Auto-fix lint issues: uv run ruff check --fix .

Git Hooks (pre-commit)

The repo ships a .pre-commit-config.yaml. After cloning, install both hook stages once:

uv run pre-commit install --hook-type pre-commit --hook-type pre-push

pre-commit (~5–15 s) β€” runs on every git commit against staged files:

  • trim trailing whitespace, end-of-file-fixer, check-yaml, check-toml, check-added-large-files, check-merge-conflict, detect-private-key
  • ruff check --fix (auto-fix lint)
  • ruff format

pre-push (~30–60 s) β€” runs on every git push:

  • uv run pytest β€” full test suite must pass before code leaves the machine.

To run all hooks manually against the whole repo: uv run pre-commit run --all-files.

Metrics (Prometheus)

prometheus-fastapi-instrumentator collects metrics for every handled request. The /metrics endpoint (root path, outside /api/v1, hidden from Swagger) exposes them in the standard Prometheus exposition format. Default metrics: request count, latency histograms, in-progress requests, exceptions per handler, plus the standard Python runtime + process metrics. Health endpoints and /metrics itself are excluded from instrumentation to avoid noise.

Auth model β€” three layers:

  1. include_in_schema=False β€” the endpoint is invisible in Swagger / OpenAPI.
  2. Environment-gated bearer token β€” outside ENVIRONMENT="local", the endpoint requires Authorization: Bearer ${METRICS_TOKEN}. Mismatched or missing tokens return 404 (not 401/403) so the endpoint's existence is not disclosed.
  3. origin_check_middleware β€” browser cross-origin requests with a foreign Origin header are rejected by the global middleware, regardless of the token.

Local dev β€” open access:

curl http://localhost:8000/metrics

Production / staging β€” bearer token required:

# .env (or your secret store)
METRICS_TOKEN=$(openssl rand -hex 32)

# Prometheus scrape config (prometheus.yml)
scrape_configs:
  - job_name: fastapi
    authorization:
      type: Bearer
      credentials: <your METRICS_TOKEN>
    static_configs:
      - targets: ['api.example.com:8000']

Even with the token, prefer to also restrict /metrics at the reverse proxy (Prometheus scraper IP allowlist or VPC-internal-only exposure). Defense-in-depth β€” the token is one layer, network policy is another.

Tracing (OpenTelemetry)

Metrics tell you what is slow ("p99 latency on /users/{id} doubled at 14:02"). Traces tell you why β€” a single request's full waterfall: route handler β†’ SQLAlchemy queries β†’ Redis calls β†’ outbound httpx requests, each with its own span and timing.

Opt-in by design. When OTEL_EXPORTER_OTLP_ENDPOINT is unset, init_telemetry() returns early and there is zero overhead β€” no spans created, no exporter started, no extra allocations. Local dev and the test suite stay clean.

Wiring (app/core/telemetry.py):

Layer Instrumentation What you get
FastAPI FastAPIInstrumentor Per-request span named after the route template (/users/{id}, not /users/42); /metrics and /health excluded
SQLAlchemy SQLAlchemyInstrumentor One span per query, with the SQL statement and duration
Redis RedisInstrumentor One span per Redis call (cache hits, rate-limit checks, pub/sub)
httpx HTTPXClientInstrumentor Outbound HTTP spans (e.g. disposable-email blocklist refresh)

Enabling traces: point OTEL_EXPORTER_OTLP_ENDPOINT at any OTLP/HTTP collector β€” Tempo, Jaeger, Honeycomb, the OTel Collector, etc.

# .env
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_SERVICE_NAME=fastapi-template

The SDK reads every other OTEL_* variable natively (sampler, headers, batch size, etc.) β€” see the OTel SDK environment variables reference for the full list.


πŸ“‚ Project Structure

β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ alembic/          # Alembic env + versions/ (generated migration scripts)
β”‚   β”œβ”€β”€ api/              # API Layer: routers, deps.py, exception handlers, decorators
β”‚   β”‚   └── routes/
β”‚   β”‚       β”œβ”€β”€ auth.py, users.py, health.py
β”‚   β”‚       └── admin/    # Admin surface (gated by CurrentSuperUser)
β”‚   β”œβ”€β”€ core/             # config, db, security, redis, rate_limit, email, messages/
β”‚   β”œβ”€β”€ models/           # Domain Layer: SQLAlchemy ORM (User, UserActivity, …)
β”‚   β”œβ”€β”€ repositories/     # Data Layer: async DB queries (no business rules)
β”‚   β”œβ”€β”€ schemas/          # Pydantic v2 DTOs (Create / Update / Response per domain)
β”‚   β”œβ”€β”€ services/         # Business Logic Layer: pure async functions, take AsyncSession
β”‚   β”œβ”€β”€ use_cases/        # Cross-domain orchestration (e.g. activity logging)
β”‚   β”œβ”€β”€ worker/           # arq worker β€” settings + cron jobs (e.g. account deletion)
β”‚   β”œβ”€β”€ utils/            # Helper functions (datetime, email templates)
β”‚   β”œβ”€β”€ tests/            # pytest suite (in-memory SQLite, fakeredis, mocked SMTP)
β”‚   └── main.py           # FastAPI app, lifespan, CORS + origin middleware
β”œβ”€β”€ alembic.ini           # Alembic settings
β”œβ”€β”€ docker-compose.yaml   # Compose stack: backend + worker + db + redis
β”œβ”€β”€ dockerfile            # Backend image (uv-based multi-stage build)
β”œβ”€β”€ pyproject.toml        # Project dependencies and tool configurations
β”œβ”€β”€ pytest.ini            # Pytest settings
└── uv.lock               # Dependency lock file (commit alongside dep changes)

🀝 Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

This project follows Conventional Commits.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'feat: Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

πŸ“„ License

Distributed under the MIT License. See the LICENSE file at the root of the workspace for more information.

About

Production-ready FastAPI template with layered architecture, async SQLAlchemy, Alembic, JWT auth, rate limiting, Sentry, Docker, and pytest. Pairs with kemalcalak/NextJS-Template.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors