Public entry point of web-base: the handler that wires the base together and the server lifecycle. A library the host calls; it never calls the host back except through the functions the host hands it (SPEC §3).
The wiring convention IS the product, so here it is, outermost first:
request-id → security headers → proxy (opt-in) → [/wb/ assets → host static → ] session → params → i18n → csrf → subject → ring-handler router, per matched route: error → gate → render → coercion → handler default handler: 404 / 405 / nil-handler 500
Static assets answer before the session: a stylesheet fetch must not mint a session cookie, and a cookie on an asset defeats shared caches. They still carry the request id and the security headers. Session sits outside subject (the subject function reads the session) and outside csrf (the token lives in the session); params sits outside csrf because the token may arrive as a form field; i18n sits outside csrf so a refused request's error page speaks the negotiated language. Error sits outside gate and render inside the router: a predicate or a layout may throw, and a refusal is an error datum. The default handler runs outside router middleware, so the request id, the session and the security headers reach it from the outer stack while errors render on their own.
Public entry point of web-base: the handler that wires the base together and
the server lifecycle. A library the host calls; it never calls the host back
except through the functions the host hands it (SPEC §3).
The wiring convention IS the product, so here it is, outermost first:
request-id → security headers → proxy (opt-in)
→ [/wb/ assets → host static → ] session → params → i18n → csrf → subject
→ ring-handler
router, per matched route: error → gate → render → coercion → handler
default handler: 404 / 405 / nil-handler 500
Static assets answer before the session: a stylesheet fetch must not mint a
session cookie, and a cookie on an asset defeats shared caches. They still
carry the request id and the security headers. Session sits outside subject
(the subject function reads the session) and outside csrf (the token lives
in the session); params sits outside csrf because the token may arrive as a
form field; i18n sits outside csrf so a refused request's error page speaks
the negotiated language. Error sits outside gate and render inside the
router: a predicate or a layout may throw, and a refusal is an error datum.
The default handler runs outside router middleware, so the request id, the
session and the security headers reach it from the outer stack while errors
render on their own.(handler {:keys [routes coercion subject-fn login-path static error-layout i18n
security csrf]
:as config})Builds the Ring handler from the host's config:
:routes reitit route data; per route :wb/layouts and :wb/gate
:session {:key base64-or-bytes} or {:store s} (required)
:subject-fn request → subject or nil (default: always nil)
:login-path where a refusal without a subject goes (required iff a route has :wb/gate)
:coercion a reitit coercion, passed through (optional)
:static create-resource-handler options for the host's assets (optional)
:error-layout slot function for error pages (optional)
:i18n {:dict … :default-locale … :locale-fn …} (optional)
:security {:frame-options … :csp … :hsts … :proxy? …} (optional)
:csrf false to disable the anti-forgery token (on for anything else, nil included)
Unknown keys are the host's own business. Every failure of a required or malformed value is raised here, at construction.
Builds the Ring handler from the host's config:
:routes reitit route data; per route `:wb/layouts` and `:wb/gate`
:session `{:key base64-or-bytes}` or `{:store s}` (required)
:subject-fn request → subject or nil (default: always nil)
:login-path where a refusal without a subject goes (required iff a route has :wb/gate)
:coercion a reitit coercion, passed through (optional)
:static create-resource-handler options for the host's assets (optional)
:error-layout slot function for error pages (optional)
:i18n `{:dict … :default-locale … :locale-fn …}` (optional)
:security `{:frame-options … :csp … :hsts … :proxy? …}` (optional)
:csrf false to disable the anti-forgery token (on for anything else, nil included)
Unknown keys are the host's own business. Every failure of a required or
malformed value is raised here, at construction.(rerender request path form)The page at path rendered again for the request a handler is answering, with
form — whatever the host's view reads, typically {:values … :errors …} — under
:wb/form, and status 422 when the page renders as an ordinary 200.
For a classic form that failed validation: the POST handler validates, and on
failure answers (rerender request "/things" {:values v :errors e}), so the
person gets the page they were on with what they typed and why it was refused —
without a redirect that loses both, and without the POST handler rebuilding the
page it does not own. The page's own :get handler runs, compiled as the router
compiled it: its gate, coercion and layouts apply as for any GET of that path. The
request keeps its session, subject, locale and CSRF token; its form, body and
parameters are dropped, and path's own path and query parameters take their
place. Views read (:wb/form request), whose shape is the host's.
A response the page answers with a redirect, an HX-Redirect or any status other
than 200 is returned as it is. An htmx form that swaps only itself wants
response/unprocessable with its own fragment instead, since the page's GET would
render the whole page's content into the form's target.
Throws when path has no :get route, and when the request already carries
:wb/form — a page that re-rendered into itself would never stop. Not a validation
helper: the base still knows no schema (SPEC §7).
path is the host's own route, never input from the request. Whatever GET it
names runs as a side effect of this POST, as the caller — a logout, a link's
redemption — so a path taken from a form field would let whoever submits it choose
which.
The page at `path` rendered again for the request a handler is answering, with
`form` — whatever the host's view reads, typically `{:values … :errors …}` — under
`:wb/form`, and status 422 when the page renders as an ordinary 200.
For a classic form that failed validation: the POST handler validates, and on
failure answers `(rerender request "/things" {:values v :errors e})`, so the
person gets the page they were on with what they typed and why it was refused —
without a redirect that loses both, and without the POST handler rebuilding the
page it does not own. The page's own `:get` handler runs, compiled as the router
compiled it: its gate, coercion and layouts apply as for any GET of that path. The
request keeps its session, subject, locale and CSRF token; its form, body and
parameters are dropped, and `path`'s own path and query parameters take their
place. Views read `(:wb/form request)`, whose shape is the host's.
A response the page answers with a redirect, an `HX-Redirect` or any status other
than 200 is returned as it is. An htmx form that swaps only itself wants
`response/unprocessable` with its own fragment instead, since the page's GET would
render the whole page's content into the form's target.
Throws when `path` has no `:get` route, and when the request already carries
`:wb/form` — a page that re-rendered into itself would never stop. Not a validation
helper: the base still knows no schema (SPEC §7).
**`path` is the host's own route, never input from the request.** Whatever GET it
names runs as a side effect of this POST, as the caller — a logout, a link's
redemption — so a path taken from a form field would let whoever submits it choose
which.(start handler {:port n}) → {:server s :port n}.
`(start handler {:port n})` → `{:server s :port n}`.
Stops the handle returned by start.
Stops the handle returned by `start`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |