Building 10 Python Packages for Enterprise FastAPI Apps: What I Learned

Published: (December 16, 2025 at 07:20 PM EST)
4 min read
Source: Dev.to

Source: Dev.to – Building 10 Python Packages for Enterprise FastAPI Apps: What I Learned

Cover image for “Building 10 Python Packages for Enterprise FastAPI Apps: What I Learned”

Daniel Garza

After a year of building enterprise platforms, I kept solving the same problems:

  • How do I handle JWT auth with RBAC that actually scales?
  • Why does every project need its own logging configuration?
  • How do I manage secrets across Azure Key Vault and local development?
  • What’s the cleanest way to handle database connection pooling?

So I extracted the patterns into 10 reusable packages and open‑sourced them.

The Netrun Service Library

All packages are MIT‑licensed and available on PyPI:

pip install netrun-auth netrun-logging netrun-config

The Foundation Layer

netrun-logging – Structured logging that doesn’t suck

  • Built on structlog for ~2.9× performance improvement over the standard library.
  • Key feature: automatic redaction of sensitive fields.
from netrun_logging import get_logger

logger = get_logger(__name__)

# The password field is automatically redacted
logger.info(
    "user_login",
    username="daniel",
    password="secret123",   # Logged as "password": "[REDACTED]"
    ip_address="192.168.1.1",
)

netrun-errors – Exception hierarchy that maps to HTTP

  • Use typed errors instead of generic Exceptions.
  • Each error class corresponds to an appropriate HTTP status code.
from netrun_errors import NotFoundError, ValidationError
from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
async def get_user(user_id: str):
    user = await db.get_user(user_id)
    if not user:
        # Raises a 404 response automatically
        raise NotFoundError("User", user_id)
    return user

The Auth Layer

netrun-auth – JWT + RBAC + Multi‑tenant isolation

This was the hardest component to get right. It uses Casbin for policy‑based access control.

from netrun_auth import JWTAuthenticator, require_permission

auth = JWTAuthenticator(
    secret_key="your-secret",
    algorithm="HS256"
)

@app.get("/admin/users")
@require_permission("users:read")
async def list_users(user=Depends(auth.get_current_user)):
    # Only users with the `users:read` permission can access this endpoint
    return await get_users()

The multi‑tenant isolation ensures that users can only access data belonging to their own tenant:

@require_tenant_access
async def get_tenant_data(tenant_id: str, user=Depends(auth.get_current_user)):
    # Automatically validates: user.tenant_id == tenant_id
    return await db.get_tenant_data(tenant_id)
  • JWTAuthenticator – handles token creation/validation.
  • require_permission – decorator that checks the required Casbin permission.
  • require_tenant_access – decorator that enforces tenant‑level isolation.

The Config Layer

netrun-config – Azure Key Vault with local fallback

Works in production with Azure Key Vault and locally with .env files:

from netrun_config import AzureKeyVaultConfig

config = AzureKeyVaultConfig(
    vault_url="https://my-vault.vault.azure.net",
    cache_ttl=300,  # Cache secrets for 5 minutes
)

# In production: fetches from Key Vault
# Locally: falls back to environment variables
db_password = await config.get_secret("database-password")
  • Production – Secrets are retrieved directly from Azure Key Vault.
  • Local development – If the vault cannot be reached, the config falls back to environment variables (e.g., those loaded from a .env file).

The LLM Layer

netrun-llm – Multi‑provider orchestration

netrun‑llm abstracts away the differences between LLM providers, allowing you to switch or fall back between them seamlessly.

from netrun_llm import LLMOrchestrator

llm = LLMOrchestrator(
    providers=["azure-openai", "ollama", "claude"],
    fallback_enabled=True,
)

# Automatically fails over if the primary provider is down
response = await llm.complete(
    prompt="Summarize this document",
    model="gpt-4",
    fallback_model="llama2",  # Use Ollama if Azure is down
)

The Data Layer

netrun-db-pool – Async SQLAlchemy that Handles Connection Storms

Connection pooling with automatic health checks

from netrun_db_pool import DatabasePool

pool = DatabasePool(
    url="postgresql+asyncpg://...",
    pool_size=20,
    max_overflow=10,
    health_check_interval=30,
)

async with pool.session() as session:
    result = await session.execute(query)
  • url – Database connection string.
  • pool_size – Number of connections kept open permanently.
  • max_overflow – Additional connections that can be created when the pool is exhausted.
  • health_check_interval – Seconds between automatic health‑check pings to keep connections alive.

The Design Philosophy

Soft Dependencies

Each package works on its own, but when several packages are installed they automatically integrate with one another:

PackagesResult
netrun-auth + netrun-loggingAuth events are automatically logged
netrun-config + netrun-loggingSecret access is audited
netrun-db-pool + netrun-errorsConnection errors are typed

The integration is performed at runtime via a simple detection pattern:

try:
    from netrun_logging import get_logger
    logger = get_logger(__name__)
except ImportError:                     # Fallback to the standard library
    import logging
    logger = logging.getLogger(__name__)

Zero‑Config Defaults

Every package ships with sensible defaults, so you can start using them immediately without any configuration:

from netrun_auth import JWTAuthenticator

# Works out‑of‑the‑box
auth = JWTAuthenticator()

# Full customisation when you need it
auth = JWTAuthenticator(
    secret_key="…",
    algorithm="RS256",
    issuer="my-app",
    audience=["api", "web"]
)

Testing First

netrun-pyte – a test‑first utility that ships with the suite (content omitted for brevity).

…additional details about the testing approach would follow here…

st‑fixtures – Unified Test Fixtures

# conftest.py
pytest_plugins = ["netrun_pytest_fixtures"]

# Your tests automatically get:
# - mock_auth:   Pre‑configured auth bypass
# - mock_db:     In‑memory SQLite
# - mock_config: Environment‑based config
# - mock_llm:    Deterministic LLM responses

What’s Next

I’m actively maintaining these packages. Current priorities:

  • Better documentation – the READMEs are a start, but a full docs site is coming.
  • More LLM providers – adding Anthropic Claude API, Google Gemini, etc.
  • OpenTelemetry tracing – unified tracing across all packages.

Try It Out

pip install netrun-auth netrun-logging netrun-config

GitHub: https://github.com/your‑org/st‑fixtures
PyPI: https://pypi.org/project/st‑fixtures/

MIT licensed. Issues and PRs are welcome!

What patterns do you use for cross‑cutting concerns in your FastAPI apps? I’d love to hear what I’m missing.

Back to Blog

Related posts

Read more »