A handler may also return a HandlerResult from ctx.response — a
redirect, most usefully — instead of the props bag. That is what makes
POST-redirect-GET expressible on a rendered route: a form handler returns
the props to re-render itself with errors, or ctx.response.redirect(...)
once the submission is accepted. HandlerResult is branded
(__handlerResult: true), so widening the union costs nothing: a props bag
of the wrong shape is still a compile error.
A zero-argument component gives P no inference site, so it widens to
unknown and any handler return is accepted — @Render(() => '<p>x</p>')
beside a handler returning an unrelated bag type-checks. The consequence is
benign rather than unsafe: the component ignores props, so the page renders
correctly and the handler has merely computed something nobody reads. It is
recorded rather than fixed because narrowing it would reject the legitimate
static-page component this case describes.
Marks a handler as a rendered route: the method returns the component's
props bag, and the framework answers with the component rendered to HTML
(text/html; charset=utf-8), never JSON.
The engine is resolved once at register() from CAPABILITIES.VIEW. A
rendered route in an application that registers no provider FAILS at
register(), naming the controller, the handler and both remedies — a
silently wrong content type (JSON where the author asked for HTML) is worse
than a startup refusal. The check is per route, so an application with no
rendered route needs no view plugin.
A FIXED status or header alongside a rendered body is declared with
@HttpCode / @ResponseHeader, which write to the response builder before
the handler runs, so the rendered HTML lands on a builder already carrying
them. A COMPUTED one goes through @Params(Ctx()). Either way the return value
IS
the props bag, so it cannot also carry a status — which is why @Render
grows no status argument of its own: that would be a third way to say what
two existing ones already say.
A handler may also return a
HandlerResultfromctx.response— a redirect, most usefully — instead of the props bag. That is what makes POST-redirect-GET expressible on a rendered route: a form handler returns the props to re-render itself with errors, orctx.response.redirect(...)once the submission is accepted.HandlerResultis branded (__handlerResult: true), so widening the union costs nothing: a props bag of the wrong shape is still a compile error.A zero-argument component gives
Pno inference site, so it widens tounknownand any handler return is accepted —@Render(() => '<p>x</p>')beside a handler returning an unrelated bag type-checks. The consequence is benign rather than unsafe: the component ignores props, so the page renders correctly and the handler has merely computed something nobody reads. It is recorded rather than fixed because narrowing it would reject the legitimate static-page component this case describes.Marks a handler as a rendered route: the method returns the component's props bag, and the framework answers with the component rendered to HTML (
text/html; charset=utf-8), never JSON.The engine is resolved once at
register()fromCAPABILITIES.VIEW. A rendered route in an application that registers no provider FAILS atregister(), naming the controller, the handler and both remedies — a silently wrong content type (JSON where the author asked for HTML) is worse than a startup refusal. The check is per route, so an application with no rendered route needs no view plugin.A FIXED status or header alongside a rendered body is declared with
@HttpCode/@ResponseHeader, which write to the response builder before the handler runs, so the rendered HTML lands on a builder already carrying them. A COMPUTED one goes through@Params(Ctx()). Either way the return value IS the props bag, so it cannot also carry a status — which is why@Rendergrows nostatusargument of its own: that would be a third way to say what two existing ones already say.