Skip to main content

A composable request processing pipeline for FastAPI

Project description

fastapi-request-pipeline

CI codecov PyPI Version Python 3.11+ License Code style: ruff

A composable, type-safe request processing pipeline for FastAPI. Build clean, maintainable APIs with reusable components for authentication, permissions, rate limiting, and more.

Features

  • Composable Architecture - Build complex request flows from simple, reusable FlowComponent instances
  • Type-Safe - Full type hints with strict mypy checking
  • Built-in Components - Authentication (JWT, API Key, Cookie), permissions, rate limiting, pagination, filters
  • Flow Composition - Layer and merge flows at app, router, and route levels
  • OpenAPI Integration - Automatic OpenAPI schema enrichment with security requirements
  • Debug Mode - Detailed execution traces for development
  • Extensible - Easy to create custom FlowComponent subclasses
  • Production Ready - Comprehensive test suite and production usage

Quick Start

pip install fastapi-request-pipeline
from fastapi import FastAPI, Depends
from fastapi_request_pipeline import (
    Flow,
    JWTAuthentication,
    HasRole,
    RateLimit,
    RequestContext,
    flow_dependency,
    enrich_openapi,
)

app = FastAPI()

# Define your flow
async def decode_jwt(token: str) -> dict:
    # Your JWT decoding logic
    return {"sub": "user123", "roles": ["admin"]}

admin_flow = Flow(
    JWTAuthentication(decode=decode_jwt),
    HasRole("admin"),
    RateLimit(rate=100, window_seconds=60),
)

# Use as dependency
@app.get("/admin/dashboard")
async def admin_dashboard(
    ctx: RequestContext = Depends(flow_dependency(admin_flow))
):
    return {"user": ctx.user, "message": "Welcome, admin!"}

# Enrich OpenAPI schema
enrich_openapi(app)

Core Concepts

Flow

A Flow is an ordered container of FlowComponent instances that process requests sequentially. FlowComponent instances are automatically sorted by ComponentCategory to ensure proper execution order (authentication → permissions → feature flags → throttling → filters → pagination → custom).

flow = Flow(
    JWTAuthentication(decode=decode_jwt),
    HasPermission("posts:write"),
    RateLimit(rate=100, window_seconds=60),
)

Built-in FlowComponent Classes

Built-in FlowComponent classes:

Authentication

  • JWTAuthentication - Bearer token authentication
  • APIKeyAuthentication - API key in headers
  • CookieAuthentication - Session cookies
  • AllowAnonymous - Skip authentication

Permissions

  • Authenticated - Require authenticated user
  • HasRole - Role-based access control
  • HasPermission - Permission-based access control

Rate Limiting

  • RateLimit - Configurable rate limiting with pluggable backends
  • InMemoryThrottleBackend - Default in-memory backend
  • Custom backends (e.g., Redis) via ThrottleBackend protocol

Filters & Pagination

  • QueryFilter - Extract selected query parameters into RequestContext.state
  • LimitOffset - Offset-based pagination

Flow Composition

Compose flows at different levels with merge_flows():

from fastapi_request_pipeline import merge_flows, OverrideFlow, DisableFlow

# Application-wide defaults
app_flow = Flow(
    JWTAuthentication(decode=decode_jwt),
    RateLimit(rate=1000, window_seconds=3600)
)

# Router-specific additions
admin_flow = Flow(HasRole("admin"))

# Route-specific overrides
public_flow = Flow(OverrideFlow(AllowAnonymous()))

# Merge with last-writer-wins per category
final_flow = merge_flows(app_flow, admin_flow, public_flow)

Custom FlowComponent Subclasses

Create custom FlowComponent subclasses by extending the base class:

from fastapi_request_pipeline import FlowComponent, ComponentCategory

class AuditLog(FlowComponent):
    category = ComponentCategory.CUSTOM

    async def resolve(self, ctx: RequestContext) -> None:
        await log_request(ctx.user, ctx.request.url.path)

Documentation

Requirements

  • Python 3.11+
  • FastAPI 0.100+

Development

# Install with dev dependencies
uv sync --extra dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov

# Lint
uv run ruff check .

# Format
uv run ruff format .

# Type check
uv run mypy --strict src/

Why Use This Library?

Instead of this:

@app.get("/posts")
async def get_posts(request: Request):
    # Authentication
    token = request.headers.get("Authorization")
    if not token or not token.startswith("Bearer "):
        raise HTTPException(401)
    user = decode_jwt(token[7:])

    # Permission check
    if "posts:read" not in user.permissions:
        raise HTTPException(403)

    # Rate limiting
    if not check_rate_limit(user.id):
        raise HTTPException(429)

    # Pagination
    limit = int(request.query_params.get("limit", 20))
    offset = int(request.query_params.get("offset", 0))

    # Business logic
    return get_posts_from_db(limit, offset)

Write this:

posts_flow = Flow(
    JWTAuthentication(decode=decode_jwt),
    HasPermission("posts:read"),
    RateLimit(rate=100, window_seconds=60),
    LimitOffset(default_limit=20),
)

@app.get("/posts")
async def get_posts(ctx: RequestContext = Depends(flow_dependency(posts_flow))):
    pagination = ctx.state["pagination"]
    return get_posts_from_db(pagination["limit"], pagination["offset"])

Benefits:

  • Separation of concerns - Security logic separated from business logic
  • Reusability - Define flows once, use across multiple endpoints
  • Composability - Mix and match FlowComponent instances, override at any level
  • Maintainability - Changes to auth/permissions in one place
  • Type safety - Full type hints and IDE support
  • Testability - FlowComponent instances are easy to unit test
  • Documentation - OpenAPI schema automatically reflects security requirements

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

fastapi_request_pipeline-0.1.3.tar.gz (102.7 kB view details)

Uploaded Source

Built Distribution

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

fastapi_request_pipeline-0.1.3-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_request_pipeline-0.1.3.tar.gz.

File metadata

  • Download URL: fastapi_request_pipeline-0.1.3.tar.gz
  • Upload date:
  • Size: 102.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fastapi_request_pipeline-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a7434088f085c5358c85ec06aac6310095375ff480b451bbe97f2d1c58fa4c99
MD5 1a409c41954ee1a603dea69c582eab06
BLAKE2b-256 910fdd961b749d50d4cff04767a4527ef204021e89b40e18f23eb441ca08a3ad

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_request_pipeline-0.1.3.tar.gz:

Publisher: release.yml on MaksimShevtsov/fastapi-request-pipeline

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

File details

Details for the file fastapi_request_pipeline-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_request_pipeline-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 f21cdd93dd27c33eaafd0497307a0eed440263d0cc948be1e356ee045aaa7f0a
MD5 6fc5a8766f22738cb8c368a3e991f963
BLAKE2b-256 3a40bff850368bb37f78e930c70db203dcf437e1b72deea339e51bae84e17cd7

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_request_pipeline-0.1.3-py3-none-any.whl:

Publisher: release.yml on MaksimShevtsov/fastapi-request-pipeline

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