Skip to main content

Batteries-included FastAPI building blocks: auth, database, events, permissions, email, pagination, Redis, rate limiting, health checks.

Project description

qstack

Batteries-included building blocks for FastAPI: auth with account activation, async SQLAlchemy, role-based permissions, an in-process event bus, pagination, Redis utilities, email, health checks.

What is this?

Most FastAPI projects rebuild the same foundation from scratch: JWT auth, database layer, exception handling, pagination, Redis helpers, middleware. qstack ships all of it as composable primitives you drop into any async project. It's not a framework — no magic, no required directory layout, no hidden global state. Every component is a factory you wire up yourself.

Features

Feature Description
App factory create_app() pre-wires exception handlers, CORS, request logging
Settings QSettings via pydantic-settings with .env and SMTP mixin
Async SQLAlchemy Base with id/created_at/updated_at, engine/session factories
Repository BaseRepository[T] CRUD + filtering + pagination + optional event emission
Service layer BaseService[T] with ownership checks
Auth JWT, bcrypt, brute-force protection, /auth/register, /auth/login, /auth/me
Account activation Redis-backed UUID tokens, auto-email, /auth/activate/{token}, /auth/resend-activation
Events In-process EventBus with sync+async listeners, auto-emitted from repo/service
Permissions Role/Permission models, PolicyEnforcer, require_permission / require_role deps
Exceptions QException hierarchy auto-converts to JSON
Pagination PaginationParams dependency + generic PaginatedResponse[T]
Redis Client factory, JSON cache, rate limiter, token blacklist
Email EmailService (SMTP + Jinja2 templates), send, send_template, send_bulk
Health /health endpoint verifying DB connectivity
Logging middleware Method, path, status, duration per request

Installation

pip install qstack                 # Core only
pip install qstack[postgres]       # + asyncpg, psycopg2-binary
pip install qstack[redis]          # + redis
pip install qstack[all]            # All extras
pip install qstack[all,dev]        # + pytest, ruff, fakeredis, aiosqlite

Python 3.10+.

Quick Start

# main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI

from qstack.app import create_app
from qstack.auth.models import UserMixin
from qstack.auth.router import create_auth_router
from qstack.config import QSettings
from qstack.database.base import Base
from qstack.database.dependencies import get_db as _get_db
from qstack.database.session import create_engine, create_session_factory
from qstack.health.router import create_health_router


class User(UserMixin, Base):
    __tablename__ = "users"


settings = QSettings(DATABASE_URL="sqlite+aiosqlite:///./app.db")
engine = create_engine(settings.DATABASE_URL)
SessionLocal = create_session_factory(engine)


async def get_db():
    async for s in _get_db(SessionLocal):
        yield s


def user_factory(email, username, hashed_password):
    return User(email=email, username=username, hashed_password=hashed_password)


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield
    await engine.dispose()


app = create_app(settings, title="Demo", lifespan=lifespan)
app.include_router(create_auth_router(
    user_model=User,
    get_db=get_db,
    jwt_secret=settings.JWT_SECRET,
    jwt_algorithm=settings.JWT_ALGORITHM,
    access_token_expire_minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES,
    user_factory=user_factory,
))
app.include_router(create_health_router(engine))
pip install "qstack[all]" uvicorn aiosqlite
uvicorn main:app --reload

Available: POST /auth/register, POST /auth/login, GET /auth/me, GET /health.

To enable account activation add redis_client=redis, email_service=email, require_activation=True to create_auth_router. See DOCUMENTATION.md — Account Activation.

Project Structure

my_api/
├── app/
│   ├── main.py           # create_app, mount routers
│   ├── config.py         # Settings(QSettings)
│   ├── database.py       # engine, SessionLocal, get_db
│   ├── models.py         # SQLAlchemy models (Base subclasses)
│   ├── repositories.py   # BaseRepository subclasses
│   ├── services.py       # BaseService subclasses
│   ├── routers/          # domain routes
│   └── policies/         # PolicyEnforcer classes
├── alembic/
├── requirements.txt
└── .env

See DOCUMENTATION.md.

Documentation

  • DOCUMENTATION.md — full library API reference, examples, integration guide.
  • CLI.mdqstack CLI reference (project scaffolding, code generation, Alembic wrappers, dev/test/doctor).

CLI (qstack)

pip install qstack-cli

qstack new my-api              # interactive project scaffold
qstack generate crud Task      # model + schema + repo + service + router
qstack db migrate "init"       # alembic autogenerate wrapper
qstack dev                     # docker compose up + uvicorn --reload
qstack doctor                  # health check

Full reference: CLI.md.

Configuration

QSettings loads from env vars / .env:

Variable Default Notes
DATABASE_URL postgresql+asyncpg://... async DB URL
DATABASE_SYNC_URL postgresql+psycopg2://... for Alembic
JWT_SECRET change-me sign tokens
JWT_ALGORITHM HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES 30
JWT_REFRESH_TOKEN_EXPIRE_MINUTES 10080 7 days
CORS_ORIGINS ["*"]
REDIS_URL redis://localhost:6379/0
SMTP_HOST localhost
SMTP_PORT 587
SMTP_USERNAME ""
SMTP_PASSWORD ""
SMTP_FROM_EMAIL noreply@example.com
SMTP_USE_TLS True

Subclass to add project-specific fields:

from qstack.config import QSettings

class Settings(QSettings):
    STRIPE_API_KEY: str = ""

settings = Settings()

Contributing

git clone https://github.com/yourname/qstack.git
cd qstack
pip install -e ".[all,dev]"
pytest
ruff check qstack/

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qstack-0.2.0.tar.gz (35.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qstack-0.2.0-py3-none-any.whl (55.4 kB view details)

Uploaded Python 3

File details

Details for the file qstack-0.2.0.tar.gz.

File metadata

  • Download URL: qstack-0.2.0.tar.gz
  • Upload date:
  • Size: 35.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qstack-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7b04ed6ae9a71ade01d816b9381fa7acd1ee29cba993ea6d2be24f51913b6ba4
MD5 f74075e1edbca700d1fed67f7e804e93
BLAKE2b-256 89f5c072ff150ee66a5d31bad02e3b19035298db8f3543fd7772e9602a1a46d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for qstack-0.2.0.tar.gz:

Publisher: workflow.yml on QukzScpz/fastapi-q-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qstack-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: qstack-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 55.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qstack-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 13e6f3c951306751b9043dde8e2e53078475c49034e1c859381584121c1d4802
MD5 e59ca204a549a55339e3b8ea6a2f0911
BLAKE2b-256 4d778fe4e8ab474c477720f19c96fb5ac53fb7468dc08d06d9bdf533e4b9564a

See more details on using hashes here.

Provenance

The following attestation bundles were made for qstack-0.2.0-py3-none-any.whl:

Publisher: workflow.yml on QukzScpz/fastapi-q-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page