-- app.wo — the assembly: an App holds the middleware chain and the route -- table, satisfies internal's Dispatcher interface, and serves. -- -- let app = App { middleware: [], routes: [] }; -- app.use_mw(Mw { m: Auth { token: t } }); -- app.add(Route { method: "GET", pattern: "/products/:id", h: Show {} }); -- return app.serve("127.0.0.1", port); -- -- Dispatch order: middleware in registration order (a Resp short-circuits), -- then the first matching route (method + pattern), else the framework 404. -- The serve loop wraps dispatch in `try`, so a trapping handler answers 500 -- and the server survives. use http use router -- iteration 17: the serve loop is library-internal now (internal/serve.wo). -- Legal here: the `internal/` boundary refuses CONSUMERS, not the library. use internal pub class App { middleware: multi Mw routes: multi Route fn use_mw(take m: Mw) { push(self.middleware, m); } fn add(take r: Route) { push(self.routes, r); } -- Registration helpers — the ctor-literal-into-take shape, per method. fn get(pattern: Text, take h: Handler) { push(self.routes, Route { method: "GET", pattern: pattern, h: h }); } fn post(pattern: Text, take h: Handler) { push(self.routes, Route { method: "POST", pattern: pattern, h: h }); } fn put(pattern: Text, take h: Handler) { push(self.routes, Route { method: "PUT", pattern: pattern, h: h }); } fn delete_(pattern: Text, take h: Handler) { push(self.routes, Route { method: "DELETE", pattern: pattern, h: h }); } fn dispatch(mut req: Req) -> Resp { for mw in self.middleware { let short = mw.m.before(req); if short != nil { return short; } } -- Path-first matching so a wrong-method hit on a known path answers -- 405 with the Allow header (registration order) instead of a 404. let allow = ""; for r in self.routes { let params: map = {}; if route_match(r.pattern, req.path, params) { if r.method == req.method { -- captures land on the borrowed request itself (mut) — a failed -- match above never touched it, since captures collect locally for k, v in params { req.params[k] = v; } return r.h.handle(req); } if allow == "" { allow = "${r.method}"; } else { allow = "${allow}, ${r.method}"; } } } if allow != "" { return method_not_allowed(allow); } return not_found(); } fn serve(host: Text, port: Int) -> Int { return internal.serve(host, port, self); } }