Router in flare.http.router is a runtime-driven
dispatcher: patterns are parsed into segment lists at registration
time and scanned linearly on every request. That's a fine default
when routes are registered dynamically or come from user input, but
it leaves two concrete wins on the table when the route table is
known at compile time:
- Zero start-up work. Segment parsing for every route happens at
compile time via
comptime for over the comptime routes
list. Nothing allocates at module import time.
- Monomorphised dispatch. The serve loop unrolls per-route via
comptime for so each iteration's literal / param / wildcard
decision is a compile-time constant and the compiler can inline
the per-route work. No List[_Route] iteration at runtime.
Usage mirrors the runtime Router:
from flare.http import (
ComptimeRoute, ComptimeRouter, Request, Response, Method, ok,
)
def home(req: Request) raises -> Response:
return ok("home")
def get_user(req: Request) raises -> Response:
return ok("user=" + req.param("id"))
comptime ROUTES: List[ComptimeRoute] = [
ComptimeRoute(Method.GET, "/", home),
ComptimeRoute(Method.GET, "/users/:id", get_user),
]
def main() raises:
var r = ComptimeRouter[ROUTES]()
# r is a Handler; pass to HttpServer.serve.
All three fields of ComptimeRoute (method, pattern, handler) are
comptime values, so the dispatch loop monomorphises fully per route.
Because every handler shares a common def(Request) raises -> Response signature, the list is homogeneous and can live as a
comptime constant — no separate set_handler step, no runtime
handler-index book-keeping.
Same status-code contract as Router: unknown path → 404, known
path wrong method → 405 with a synthesised Allow: header. Path
parameters captured by a match land in req.params_mut() just
like the runtime router.