HTTP Pipeline
Copy-Paste Example
/assets/logo.svg and /assets/icons/logo.svg match, while /assets does not. The controller reads the portable declaration name rather than find-my-way’s internal wildcard key:
ctx.params.paths is icons/logo.svg for /assets/icons/logo.svg. Dynamic names must be unique across the complete route and cannot be __proto__, prototype, or constructor. Static routes win over [id], and [id] wins over [...paths]. Routes with the same structure but different parameter names conflict during loading. A configured prefix may use native /:tenant or bracket-style /[tenant] parameters and is compiled separately from portable file segments. Use http.route() when deliberately registering native find-my-way syntax by hand; native syntax is not accepted in file names.
More Examples
safeParse().data back to ctx.request.body.
Trusted reverse proxy
Http does not trust forwarded headers by default. When the listener is reachable only through a controlled reverse proxy, enable Koa’s proxy semantics explicitly and bound the number of proxy IPs that may be read:
X-Forwarded-Proto and the configured client-IP header. It must send X-Forwarded-Proto: https after TLS termination so ctx.protocol, ctx.secure, and Secure Cookie handling reflect the public connection. Keep the Hile listener inaccessible to untrusted direct clients: proxy: true trusts these headers and is not itself a network trust boundary.
Use proxyIpHeader only when the deployment uses a client-IP header other than X-Forwarded-For. maxIpsCount bounds the proxy chain read from that header; set it to the known number of trusted hops instead of relying on Koa’s unbounded default.
HttpProps composes Koa’s complete constructor options with Hile’s port and find-my-way options. Koa settings such as env, subdomainOffset, keys, asyncLocalStorage, proxy, proxyIpHeader, and maxIpsCount are passed through without a Hile-owned mirror or a second Hile-specific option contract.
Runtime And Lifecycle Notes
new Http({ port })creates a Koa app from the completeHttpPropsobject and afind-my-wayrouter.proxydefaults tofalse. When enabled,proxyIpHeaderandmaxIpsCountare passed to Koa before any middleware or controller handles requests.http.use(middleware)registers Koa middleware beforelisten().http.listen()returns a close function.http.load(directory, options)scans*.controller.{ts,js,tsx,jsx,mjs}by suffix..d.tsdeclarations and.js.mapsource maps are never controller routes.- File loading is atomic: invalid syntax, import failure, invalid exports, or conflicts unregister the routes already acquired by that batch.
defineController()supports method-only, method-plus-middlewares, and metadata-plus-Zod forms.- Response plugins transform handler return values and set
ctx.bodywhen the final result is notundefined.
Anti-Patterns
- Setting
ctx.bodyand returning a value from the same controller. - Loading controllers after starting only because an old example does it; prefer load before listen in new code.
- Using old validation examples that assume Zod coercion rewrote
ctx.query. - Enabling
proxyon a listener that untrusted clients can reach directly, or allowing an edge proxy to preserve client-supplied forwarded headers.
Verification Checklist
- Controller files default-export
defineController(...)or an array of controllers. - Required catch-all controllers use
[...name].controller.ts, keep it as the final segment, and read the slash-joined value fromctx.params.name. - Controllers return response values.
- Boot service awaits
http.load()beforehttp.listen(). - Zod schemas are used for validation, and parsed data is explicitly parsed when needed.
- Reverse-proxy deployments replace forwarded headers, protect the direct listener, and set
maxIpsCountto the known proxy-hop count.