loom.rest.middleware

ASGI middleware for the Loom REST layer.

All middleware in this module is framework-agnostic — pure ASGI callables that work with FastAPI, Starlette, Litestar, Django ASGI, or any ASGI server (uvicorn, hypercorn, daphne).

No FastAPI or Starlette types are imported here.

Functions

_accepted_trace_id(candidate)

Return the caller's trace id when it is safe to echo, else a fresh one.

_extract_header(headers, name)

Return the first header value matching name (lowercase bytes).

Classes

TraceIdMiddleware(app, *[, header])

ASGI middleware that propagates a trace identifier per request.

class loom.rest.middleware.TraceIdMiddleware(app, *, header='x-request-id')[source]

Bases: object

ASGI middleware that propagates a trace identifier per request.

On each HTTP request:

  1. Reads the configured header (default x-request-id).

  2. Uses its value as the trace-id when it matches the accepted charset ([A-Za-z0-9._-], 1-128 chars); generates a UUID4 otherwise. A client-supplied identifier is echoed back and reaches every log line, so an unvalidated one is a log-forging primitive.

  3. Activates the trace-id in the current async context via set_trace_id().

  4. Injects the trace-id into the response headers so clients can correlate logs.

  5. Resets the context after the response is sent.

Non-HTTP scopes (WebSocket, lifespan) are passed through unchanged.

Parameters:
  • app (_ASGIApp) – The ASGI application to wrap.

  • header (str) – HTTP header name to read/write (case-insensitive, stored as lowercase bytes internally). Defaults to "x-request-id".

Example — FastAPI:

from loom.rest.middleware import TraceIdMiddleware

app = create_fastapi_app(result, RouteSources(python=[...]))
app.add_middleware(TraceIdMiddleware)

Example — plain ASGI composition:

app = TraceIdMiddleware(your_asgi_app)