benzene.http
The inbound HTTP (ASGI) transport binding: host the handlers you wrote against benzene.core
behind a real HTTP server. Distribution: benzene-http (depends on benzene-core).
pip install benzene-http
Overview
BenzeneHttpApp is a standard ASGI application implementing the HTTP binding from the specification
(transport-bindings §2):
- Topic — resolved from route/method conventions via an
HttpRouter. - Headers — HTTP headers flow in and out, both directions.
- Status — the handler's Benzene status maps to an HTTP code via wire-contracts §4.1.
- Scope — one DI scope and exactly one pipeline invocation per request.
- Failure — unmatched route →
404, invalid JSON body →400, uncaught handler error →503. The host is never crashed by request content.
Routing
Pair @http_endpoint(method, path) with @message(topic). The HTTP decorator says where a
request arrives; @message says which handler it resolves to. Stack @http_endpoint to give one
handler several routes.
from benzene.core import message
from benzene.results import Result
from benzene.http import BenzeneHttpApp, HttpRouter, http_endpoint
@http_endpoint("GET", "/orders/{id}")
@message("order:get")
async def get_order(request: dict) -> Result:
return Result.ok({"id": request["id"]})
app = BenzeneHttpApp(HttpRouter().add(get_order)) # run: uvicorn module:app
{name}placeholders match a single path segment and are surfaced as request fields.- Routes match in registration order, first match wins; the method must also match.
- Explicit registration without decorators:
HttpRouter().register("GET", "/orders/{id}", "order:get", get_order).
How the request is assembled
The handler's request is the JSON body object merged with the query string and then the captured
path parameters — path wins, then query, then body. So /orders/{id} delivers id as a request
field even if the body also has one.
Status mapping
to_http(status) and from_http(code) implement the wire-contracts §4.1 table:
from benzene.http import to_http, from_http
to_http("ok") # 200
to_http("created") # 201
to_http("not-found") # 404
from_http(422) # "validation-error"
BenzeneHttpApp
BenzeneHttpApp(router, application=None, pipeline=None, container=None)
By default it builds a BenzeneMessageApplication from the router's handler definitions. Pass your
own application (or a pipeline / container) to add middleware or DI registrations.
Two ways to invoke it:
await app.handle(method, path, query_string="", headers=None, body="")→ anHttpResponse(status_code,headers,body) — convenient in tests.await app(scope, receive, send)— the raw ASGI entry point for uvicorn/hypercorn.
Exports
BenzeneHttpApp, HttpResponse, HttpRouter, HttpEndpoint, http_endpoint, routes_of,
to_http, from_http.
See also
benzene.core— the handlers and pipeline this binding hosts.- Getting started — a full HTTP service from scratch.
- transport-bindings §2 — the binding contract.