Middleware¶
A middleware is a function that wraps an endpoint handler. It receives the endpoint and returns a new handler:
def my_middleware(endpoint):
async def wrapper():
# Before handler
print("before")
result = await endpoint()
# After handler
print("after")
return result
return wrapper
Warning
Do NOT use @functools.wraps on middleware wrappers. The framework raises RuntimeError if it detects this, because functools.wraps copies attributes that interfere with parameter binding and OpenAPI generation.
Applying Middleware¶
Per-Route with @ Operator¶
from kui.asgi import HttpRoute, required_method, allow_cors
route = HttpRoute("/data", handler) @ required_method("GET") @ allow_cors()
app.router <<= route
Middleware is applied right-to-left: allow_cors wraps first, then required_method.
Per-Route via Decorator Parameter¶
Per-Routes Group¶
from kui.asgi import Routes, HttpRoute
routes = Routes(
HttpRoute("/a", handler_a),
HttpRoute("/b", handler_b),
http_middlewares=[auth_middleware, logging_middleware],
)
Or register with a decorator:
routes = Routes()
@routes.http_middleware
def logging_middleware(endpoint):
async def wrapper():
print(f"Request received")
return await endpoint()
return wrapper
@routes.http.get("/")
async def handler():
return "ok"
App-Level¶
app = Kui(
http_middlewares=[logging_middleware, auth_middleware],
socket_middlewares=[ws_auth_middleware], # ASGI only
)
Middleware with Parameters¶
Middleware wrappers can declare Annotated parameters for automatic request binding:
from typing_extensions import Annotated
from kui.asgi import Header
def auth_middleware(endpoint):
async def wrapper(
authorization: Annotated[str, Header(alias="authorization")],
):
if not verify_token(authorization):
raise HTTPException(401)
return await endpoint()
return wrapper
These parameters are:
- Automatically extracted from the request
- Validated via Pydantic
- Included in OpenAPI documentation
Middleware Execution Order¶
Middleware is applied in this order (outermost to innermost):
- App-level middleware (
http_middlewaresonKui) - Routes group middleware (
http_middlewaresonRoutes) - Per-route middleware (via
@operator ormiddlewares=parameter)
The handler runs last, at the innermost level.
Built-in Middleware¶
required_method¶
Restrict a handler to specific HTTP methods:
Returns 405 Method Not Allowed for non-matching methods. Returns 200 for OPTIONS requests with an Allow header.
allow_cors¶
Per-route CORS middleware:
from kui.asgi import allow_cors
route = HttpRoute("/api", handler) @ allow_cors(
allow_origins=[re.compile(r"https://example\.com")],
allow_methods=["GET", "POST"],
allow_headers=["Authorization"],
max_age=600,
)
See CORS for details.