Skip to content

blackbull.middleware.utils

blackbull.middleware.utils

Utilities for middleware authors.

Public API: - as_middleware: decorator that normalises the send callable so inner send wrappers defined by the middleware always receive a single native representation — NativeResponse on the HTTP path (H1 and H2), plain ASGI event dicts only at the external-host edge — never raw Response objects. Works on both async middleware functions and middleware classes (decorates __call__).

as_middleware(target)

Decorator that marks an async function or class as BlackBull middleware.

Wraps call_next so any send callable the middleware passes to it is automatically normalised — Response/JSONResponse objects are converted to NativeResponse before reaching the middleware's inner send wrapper. The wrapper therefore only ever sees the native representation (NativeResponse on the HTTP path — H1 and H2).

Applied to an async function (signature (conn, receive, send, call_next))::

@as_middleware
async def timing_mw(conn, receive, send, call_next):
    async def timed_send(event):
        # event is a NativeResponse on the HTTP path
        await send(event)
    await call_next(conn, receive, timed_send)

Applied to a class whose __call__ is the middleware coroutine::

@as_middleware
class Cache:
    async def __call__(self, conn, receive, send, call_next):
        async def cap_send(event):
            # event is a NativeResponse on the HTTP path
            ...
        await call_next(conn, receive, cap_send)

Power users who need to handle raw send arguments (e.g. because their middleware is used in a context where no simplified handlers are registered) should omit this decorator — their call_next is then wired directly to the next handler with no extra wrapping.