A Handler is anything that can turn a Request into a Response.
Structs with state implement it directly, functions adapt via FnHandler,
and higher-level types (Router, middleware wrappers) all
nest by wrapping another Handler.
Writing a handler as a struct
from flare.http import Handler, Request, Response, ok
struct Greeter(Handler):
var greeting: String
def serve(self, req: Request) raises -> Response:
return ok(self.greeting + " " + req.url)
Writing a handler as a plain function
from flare.http import FnHandler, Request, Response, ok
def hello(req: Request) raises -> Response:
return ok("hello")
var handler = FnHandler(hello)
FnHandler is the backwards-compatibility shim for 's
def(Request) raises -> Response signature. HttpServer.serve keeps
accepting that function signature directly; internally it wraps the
function in FnHandler and dispatches through the same Handler
codepath.
Composing handlers
Handlers compose by wrapping. Middleware is a Handler that holds an
inner Handler and does something before / around / after the inner
call:
struct Logged[Inner: Handler](Handler):
# Forward the inner handler's BodyType so the typed response
# flows through unchanged (the canonical generic-wrapper shape).
comptime BodyType = Self.Inner.BodyType
var inner: Self.Inner
var prefix: String
def serve(self, req: Request) raises -> ResponseImpl[Self.BodyType]:
print(self.prefix, req.method, req.url)
return self.inner.serve(req)
A wrapper that may substitute its own response (auth 401, error 500)
instead keeps -> Response and calls .lower() on the inner
result so both branches share the erased type.
Structs
FnHandler
struct FnHandler
Adapts a plain def(Request) raises -> Response into a Handler.
Stores the function as a runtime field (same cost as 's
existing HttpServer.serve(handler) path). Use this when you want
Router.get(path, my_fn) to accept a bare function without a
user-side wrapper struct.
For the fastest possible dispatch, implement Handler directly on
a struct (no indirection) or use HttpServer.serve[handler]() in
comptime-specialised mode (landing in Step 6).
Example:
def hello(req: Request) raises -> Response:
return ok("hello")
var h = FnHandler(hello)
var resp = h.serve(some_req)
Implements Copyable, Handler, Movable
- Fields
f: def(Request) raises thin -> Response: The wrapped function.
comptime BodyType = InlineBody
The Body impl this handler authors its response with.
__init__
def __init__(out self, f: def(Request) raises thin -> Response)
- Args
f: A function with signature def(Request) raises -> Response.
serve
def serve(self, req: Request) -> Response
Call the wrapped function with req. Inlined so the extra trait dispatch layer is eliminated and the call site reduces to a direct self.f(req) - matches 's hot path.
FnHandlerCT
struct FnHandlerCT[F: def(Request) raises thin -> Response]
Comptime-parametric adapter: the wrapped function is a type parameter, not a runtime field.
Zero-size at runtime (no var f); the compiler monomorphises
serve per F so the call site reduces to a direct,
statically-known F(req). This is what gives the Handler path
the same machine code as a bare function call in the prior HttpServer.serve(def...) shape.
Usage:
```mojo
def hello(req: Request) raises -> Response:
return ok("hello")
comptime HelloHandler = FnHandlerCT[hello]
def main() raises:
var h = HelloHandler()
var srv = HttpServer.bind(SocketAddr.localhost(8080))
srv.serve(h^)
```
Prefer FnHandlerCT[fn] over FnHandler(fn) in hot paths
where the handler identity is known at compile time (benches,
single-handler servers, comptime-composed Routers). Use the
runtime FnHandler only when the handler is chosen at runtime
(e.g. when a Router needs to store def handlers in a list
indexed at request time).
Implements Copyable, Handler, Movable
comptime BodyType = InlineBody
The Body impl this handler authors its response with.
__init__
def __init__(out self)
Default-construct the zero-size handler.
serve
def serve(self, req: Request) -> Response
Direct call to the comptime-bound function F.
WithViewCancel
struct WithViewCancel[H: Handler & Copyable]
Adapter that lets a plain Handler plug into the view-aware reactor path.
.. note::
Internal adapter. Not part of the curated public surface;
import explicitly via from flare.http.handler import WithViewCancel. The documented public path for the view
reactor is implementing :trait:ViewHandler directly.
WithViewCancel[H] materialises an owned Request from
the borrowed view via into_owned() and forwards every
request to H.serve(req). Defeats the zero-copy benefit of
the view path — use ViewHandler directly when the handler
can read body / headers / URL through the borrowed slice.
Use this adapter only when you need to plug an existing
Handler struct into a server entry point that takes
serve_view (e.g. a Router that's a Handler but must
coexist with ViewHandler-shaped sibling handlers in the
same server).
Wrapping is zero-overhead apart from the into_owned body
copy: H.serve is the only generated work after the copy.
Example:
from flare.http import HttpServer, Router, Request, Response, ok
from flare.http.handler import WithViewCancel
from flare.net import SocketAddr
def hello(req: Request) raises -> Response:
return ok("hello")
def main() raises:
var r = Router()
r.get("/", hello)
var srv = HttpServer.bind(SocketAddr.localhost(8080))
srv.serve_view(WithViewCancel[Router](r^))
Implements Copyable, Movable, ViewHandler
- Fields
inner: H: Wrapped plain handler; serve(req) is called after view.into_owned().
serve_view
def serve_view[origin: Origin[mut=origin.mut]](self, req: RequestView[origin], cancel: Cancel) -> Response
Materialise an owned Request and forward.
- Args
req: Borrowed-view request.cancel: Per-request cancel token. Ignored by the
adapter; the wrapped Handler does not observe
cancellation.
WithCancel
struct WithCancel[H: Handler & Copyable]
Adapter that lets a plain Handler plug into the cancel-aware reactor path.
WithCancel[H] ignores the cancel argument and forwards
every request to H.serve(req). Use when you have a stateful
handler that does not need to observe cancellation but the
surrounding code is using HttpServer.serve_cancellable
(because a sibling handler does, or because the user wants the
consistent type signature).
This is the design-doc "blanket impl from the existing 1-arg
Handler.serve" expressed as an explicit Mojo adapter, since
Mojo currently lacks the trait-method-overloading needed to do
it implicitly. See the CancelHandler docstring.
Wrapping is zero-overhead at runtime: the inner H.serve(req)
call is the only generated work, and Mojo monomorphises away the
adapter's struct field for stateless H.
Example:
from flare.http import (
HttpServer, Router, WithCancel, Request, Response, ok,
)
from flare.net import SocketAddr
def hello(req: Request) raises -> Response:
return ok("hello")
def main() raises:
var r = Router()
r.get("/", hello)
var srv = HttpServer.bind(SocketAddr.localhost(8080))
# Pass through the cancel-aware path even though the
# handler doesn't observe cancellation.
srv.serve_cancellable(WithCancel[Router](r^))
Implements CancelHandler, Copyable, Movable
- Fields
inner: H: Wrapped plain handler; serve(req) is called from the cancel-aware serve(req, cancel).
serve
def serve(self, req: Request, cancel: Cancel) -> Response
Ignore cancel and forward to self.inner.serve(req).
- Args
req: The incoming request.cancel: Per-request cancel token. Ignored by the
adapter; the wrapped Handler does not observe
cancellation.
WithRaises
struct WithRaises[Inner: HandlerInfallible & Copyable]
Adapt a :trait:HandlerInfallible so it fits the regular :trait:Handler constraint.
.. note::
Internal adapter. Not part of the curated public surface;
import explicitly via from flare.http.handler import WithRaises. Pairs with :trait:HandlerInfallible, which
lives behind the same import path.
Use cases:
Router.get(path, h) accepts a :trait:Handler. Wrapping
an infallible handler in :class:WithRaises lets it slot in
without rewriting the router signature.
- Middleware chains (:class:
Logger, :class:Cors, etc.)
compose against :trait:Handler. The adapter fits the
infallible handler at the bottom of the chain.
The adapter has zero runtime cost: serve is @always_inline,
forwards directly to the inner serve(req), and the only added
work is satisfying the raises contract (which the compiler
elides since the inner call is provably infallible).
The reverse adapter does NOT exist: a :trait:Handler can fail,
so it isn't safe to expose as :trait:HandlerInfallible.
Implements Copyable, Handler, Movable
- Fields
inner: Inner: The wrapped infallible handler.
comptime BodyType = InlineBody
The Body impl this handler authors its response with.
serve
def serve(self, req: Request) -> Response
Forward to self.inner.serve(req). The raises annotation is satisfied vacuously: the inner serve is infallible by construction.