Skip to main content

Beyond — FastAPI Runtime Composition Library

One line per feature. Zero magic. A normal FastAPI instance at the end.

Beyond wraps FastAPI with a fluent, opt-in composition API for configuration loading, infrastructure adapters, and authentication bootstrapping. Every integration registers through standard FastAPI mechanisms — lifespan, dependency injection, included routers — and exposes the underlying raw client objects. Nothing is hidden.

📖 Full documentation →

from beyond_fastapi import Beyond, load_settings, require_user, DbSession, RedisClient

settings = load_settings(AppSettings, yaml="settings.yaml")

app = (
    Beyond(settings)
    .sqlalchemy(config=settings.postgres)
    .redis(config=settings.redis)
    .auth.jwt_header(jwt_config=settings.jwt)
    .build()
)

@app.get("/me")
async def me(payload: dict = require_user, db: DbSession = None, cache: RedisClient = None):
    return {"sub": payload.get("sub")}

Installation

pip install beyond-fastapi        # core (fastapi, pydantic-settings, pyyaml, python-jose)

# Optional adapters — install only what you need
pip install beyond-fastapi[sqlalchemy]   # SQLAlchemy + asyncpg
pip install beyond-fastapi[redis]        # Redis
pip install beyond-fastapi[rabbitmq]     # RabbitMQ (aio-pika)
pip install beyond-fastapi[beanie]       # Beanie + Motor (MongoDB)

Python ≥ 3.11 required.


Configuration Loading

Define your settings schema with Pydantic. Drop in Beyond's config fragments or roll your own. Environment variables always win — YAML is the base.

from pydantic_settings import BaseSettings
from beyond_fastapi import load_settings, PostgresConfig, RedisConfig, JwtConfig

class AppSettings(BaseSettings):
    debug: bool = False
    postgres: PostgresConfig
    redis: RedisConfig
    jwt: JwtConfig

settings = load_settings(AppSettings, yaml="settings.yaml")

settings.yaml

debug: true
postgres:
  dsn: postgresql+asyncpg://user:pass@localhost:5432/mydb
  pool_size: 20
  echo: false
redis:
  url: redis://localhost:6379
jwt:
  secret: super-secret-key
  algorithm: HS256
  access_token_expire_seconds: 7200

Priority (highest to lowest):

  1. Environment variables
  2. .env file
  3. YAML file
  4. Field defaults
export POSTGRES__DSN=postgresql+asyncpg://prod:pass@host:5432/db  # wins over YAML

Built-in config fragments

Fragment Key fields
PostgresConfig dsn, pool_size, max_overflow, echo
RedisConfig url, max_connections
RabbitmqConfig url
BeanieConfig uri, database
JwtConfig secret, algorithm, access_token_expire_seconds

All fragments are plain pydantic.BaseModel — embed them in your own BaseSettings subclass.


Adapters

Every adapter installs its resources during startup, cleans up on shutdown, and exposes a FastAPI dependency for per-request usage. Raw clients are always accessible on app.state.beyond.

SQLAlchemy

from beyond_fastapi import Beyond, DbSession
from beyond_fastapi.config.loader import PostgresConfig

kit = Beyond(settings)
kit.sqlalchemy(config=settings.postgres)  # or: kit.sqlalchemy(dsn="postgresql+asyncpg://...")

app = kit.build()

@app.get("/users")
async def list_users(session: DbSession):
    result = await session.execute(text("SELECT id, name FROM users"))
    return [{"id": r.id, "name": r.name} for r in result]

Raw access:

engine = app.state.beyond.sqlalchemy_engine          # AsyncEngine
factory = app.state.beyond.sqlalchemy_session_factory # async_sessionmaker

Redis

from beyond_fastapi import Beyond, RedisClient

kit = Beyond(settings)
kit.redis(config=settings.redis)  # or: kit.redis(url="redis://localhost")

app = kit.build()

@app.get("/cache/{key}")
async def get_cache(key: str, cache: RedisClient):
    value = await cache.get(key)
    return {"key": key, "value": value}

Raw access:

redis = app.state.beyond.redis_client  # redis.asyncio.Redis
await redis.ping()

RabbitMQ

from beyond_fastapi import Beyond
from beyond_fastapi.deps.providers import get_rabbitmq_channel

kit = Beyond(settings)
kit.rabbitmq(config=settings.rabbitmq)  # or: kit.rabbitmq(url="amqp://guest:guest@localhost/")

app = kit.build()

@app.get("/publish")
async def publish(channel = Depends(get_rabbitmq_channel)):
    await channel.default_exchange.publish(
        aio_pika.Message(body=b"Hello!"),
        routing_key="my_queue",
    )
    return {"status": "published"}

Raw access:

conn = app.state.beyond.rabbitmq_connection  # aio_pika AbstractRobustConnection

Beanie / MongoDB

from beanie import Document
from beyond_fastapi import Beyond

class UserDoc(Document):
    name: str
    email: str
    class Settings:
        name = "users"

kit = Beyond(settings)
kit.beanie(config=settings.beanie, document_models=[UserDoc])

app = kit.build()

Raw access:

client = app.state.beyond.beanie_client  # motor.motor_asyncio.AsyncIOMotorClient

Authentication

Beyond implements the transport + strategy pattern. A backend = how the token travels (transport) + how it's generated/validated (strategy). Multiple backends can coexist — they're tried in registration order.

JWT Bearer Header

kit = Beyond(settings)
kit.auth.jwt_header(
    secret="my-secret",
    algorithm="HS256",
    expire_seconds=3600,
)

# or from config:
kit.auth.jwt_header(jwt_config=settings.jwt)
kit.auth.jwt_cookie(
    secret="my-secret",
    cookie_name="session",
    cookie_max_age=3600,
    cookie_secure=True,
)

Multiple backends (tried in order)

kit.auth.jwt_header(name="api", secret="...")
kit.auth.jwt_cookie(name="web", secret="...")

Protecting routes

from beyond_fastapi import require_user, current_user

@app.get("/me")
async def me(payload: dict = require_user):
    # raises 401 if no valid token
    return {"sub": payload.get("sub")}

@app.get("/optional")
async def optional(payload: dict = current_user):
    # payload is None if not authenticated
    return {"authenticated": payload is not None}

Custom entity names

from beyond_fastapi import make_required_auth_dependency

require_admin = make_required_auth_dependency("admin")

@app.get("/admin")
async def admin_dashboard(payload: dict = require_admin):
    ...

Login / logout router

Beyond provides an optional, minimal login/logout router:

from beyond_fastapi.auth.router import make_auth_router
from fastapi import Depends, HTTPException

async def authenticate_user(username: str, password: str) -> dict:
    """Your custom credential check. Return a dict for the JWT or raise 401."""
    if username == "admin" and password == "secret":
        return {"sub": username, "role": "admin"}
    raise HTTPException(401, "Invalid credentials")

router = make_auth_router(
    backend_name="bearer",
    kit=kit,
    get_user_data=Depends(authenticate_user),
    prefix="/auth",
)
app.include_router(router)

Dependency Cheat Sheet

Import from one place:

from beyond_fastapi.deps.providers import (
    DbSession,              # Annotated[AsyncSession, Depends(get_db_session)]
    RedisClient,            # Annotated[Redis, Depends(get_redis)]
    get_rabbitmq_channel,   # async generator — yields per-request channel
    get_rabbitmq_connection,# returns the persistent connection
    get_motor_client,       # returns AsyncIOMotorClient
    current_user,           # optional auth — dict | None
    require_user,           # required auth — dict or 401
)

Or import directly from beyond_fastapi:

from beyond_fastapi import DbSession, RedisClient, require_user

Full Application Example

# ── settings.py ──────────────────────────────────────────────────────────
from pydantic_settings import BaseSettings
from beyond_fastapi import PostgresConfig, RedisConfig, JwtConfig

class AppSettings(BaseSettings):
    debug: bool = False
    postgres: PostgresConfig
    redis: RedisConfig
    jwt: JwtConfig

# ── main.py ──────────────────────────────────────────────────────────────
from fastapi import FastAPI, Depends, HTTPException
from beyond_fastapi import Beyond, load_settings, require_user, DbSession, RedisClient

settings = load_settings(AppSettings, yaml="settings.yaml")

kit = Beyond(settings)
kit.sqlalchemy(config=settings.postgres)
kit.redis(config=settings.redis)
kit.auth.jwt_header(jwt_config=settings.jwt)
kit.auth.jwt_cookie(jwt_config=settings.jwt, cookie_name="session")

app: FastAPI = kit.fastapi(title="My API", docs_url="/api/docs")

@app.get("/me")
async def me(
    payload: dict = require_user,
    session: DbSession = None,
    cache: RedisClient = None,
):
    return {"sub": payload.get("sub")}

@app.get("/health")
async def health(cache: RedisClient = None):
    await cache.ping()
    return {"status": "ok"}

@app.get("/debug/state")
async def debug_state(request):
    state = request.app.state.beyond
    return {
        "has_db": state.sqlalchemy_engine is not None,
        "has_redis": state.redis_client is not None,
    }

Documentation

Comprehensive documentation is available in the docs/ directory:

Section Description
Getting Started Installation, core concepts, first application
Configuration load_settings, config fragments, YAML + env priority
Adapters SQLAlchemy, Redis, RabbitMQ, Beanie — detailed usage
Authentication JWT header/cookie, multi-backend, route protection, login/logout
Advanced Usage Custom adapters, app.state internals, raw access, error handling
API Reference Every public class, method, and function

Design Principles

  • Produces a normal FastAPI instance. build() returns FastAPI, not a subclass.
  • No globals. Each Beyond instance is self-contained.
  • No magic. All registrations go through standard FastAPI mechanisms (lifespan, Depends, APIRouter).
  • Escape hatches everywhere. Every adapter exposes its raw client on app.state.beyond.
  • No middleware by default. No CORS, no logging, no health checks. You add what you need.
  • No auto-detection. Your settings class is always explicit. Env vars win — that's it.

License

MIT

Metadata

Release files for beyond-fastapi 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for beyond-fastapi 0.1.1
File Size Uploaded
beyond_fastapi-0.1.1.tar.gz 103.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for beyond-fastapi 0.1.1
File Interpreter ABI Platform
beyond_fastapi-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 127.9 kB

Release files / beyond_fastapi-0.1.1.tar.gz

Download URL beyond_fastapi-0.1.1.tar.gz
Size 103.8 kB
Tags Source
SHA-256 checksum
How to use checksums
832c596ec2525d53685e3da1d5bff7640f67aa1404c74f2add91ebbc5af9073f
BLAKE2b-256 checksum
How to use checksums
e54f9cdefc4be068a05599511cb5704946160a8880d0c17d8b3dc8dcf840ee68
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release files / beyond_fastapi-0.1.1-py3-none-any.whl

Download URL beyond_fastapi-0.1.1-py3-none-any.whl
Size 24.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c22f76b7fd016ad2bb885f11cf9e9784dd0f2d765ec5ce2175983790d159c6b
BLAKE2b-256 checksum
How to use checksums
be8a80e196e3f8880f2bbb60dd753c4370850fe22e2af5b48248ade3e5be43e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page