Route REL defines HTTP entrypoints. It uses the common REL grammar while keeping HTTP authority narrow and explicit.
Structure
Current HTTP method parsing includes:
Additional methods/wildcard handlers may be added later.
File routing
Filesystem routing is active, including dynamic/catch-all parameters:
Two routes whose shapes differ only by parameter name collide at boot; [id] and [slug] are not treated as distinct URL shapes.
Request snapshot
A declared route parameter receives the bounded request snapshot:
JSON bodies are decoded directly into REL values with strict object identity. Duplicate object keys are rejected with HTTP 400 at any nesting depth instead of using last-key-wins semantics. Because REL numbers use f64, integer-valued JSON numbers must stay within -9007199254740991..=9007199254740991; larger integers are rejected with HTTP 400 instead of being silently rounded, including when nested inside arrays or objects. Finite fractional JSON numbers remain valid. Other current v1 body types are exposed as UTF-8 strings; invalid UTF-8 returns HTTP 400 rather than being replacement-decoded. Invalid JSON returns HTTP 400 and configured body-limit violations return HTTP 413 before REL execution. Route REL v1 has no first-class binary request-body value type.
Forwarded client/protocol data is trusted only when trustedProxyHeaders policy is enabled. Otherwise request.ip is derived from the socket peer. When proxy trust is enabled, every textual X-Forwarded-For field-line is consumed in HeaderMap order, comma-delimited entries are flattened in order, every token must be a valid IPv4/IPv6 literal, values are canonicalized, and request.ip uses the first resulting entry; malformed, empty-present, or non-text forwarding metadata fails with HTTP 400 instead of being ignored. X-Forwarded-Proto is handled across all field-lines with the same ordering rules: every supplied token must be http or https (ASCII case-insensitive), the first token becomes the canonical lowercase request.protocol, and malformed/empty present proxy metadata returns HTTP 400 instead of silently becoming http.
Current transport behavior joins repeatable duplicate request headers, while semantic singleton headers Content-Type, Host, User-Agent, and Content-Length are rejected when repeated so the structured snapshot cannot disagree with HTTP interpretation. When Host is present it must also parse as an HTTP authority (host or host:port, including bracketed IPv6); malformed authority text returns HTTP 400 instead of being exposed through request.host. Content-Length, when present, must be non-empty ASCII decimal digits and no greater than 9007199254740991, the largest integer REL can represent exactly; malformed or lossy values return HTTP 400 instead of becoming null or a rounded number. Credential-bearing Authorization and Proxy-Authorization headers are also fail-closed singletons during request snapshot construction: repeated field-lines (even identical ones) return HTTP 400 before field resolution or handler execution, rather than being comma-joined into a synthetic credential. Single credential values, including embedded commas, remain unchanged. There is no first-class binary-body value type.
Responses
A plain REL return value remains a JSON 200 OK response for compatibility. Import response for explicit HTTP behavior:
Header/cookie values are validated again at the Rust HTTP boundary. Cookie options include path, domain, maxAge, httpOnly, secure, and sameSite.
Streaming responses, first-class binary responses, file sends, and SSE remain later transport work.
Imports and authority
Route-safe built-in concepts include the currently registered HTTP-side capabilities such as net, json, crypto, time, http, request, log, security, response, and read-only private, subject to each capability's implemented operation set.
Important deny rules:
- Route REL cannot directly import
service:*. - Route REL cannot import/read shared
ENVby default. - Route REL cannot import
quickDB. - Route REL cannot directly import Video Manager (
vm/video-manager).
The normal route-to-service shape is Route -> Module -> Service.
Server middleware
Global HTTP middleware/policy is configured by server.server, not imported package-by-package into each route. Server REL lowers middleware into an ordered MiddlewarePlan; the backend combines applicable plan-driven settings with its native security stack.
See ../server.server/.
Runtime Image execution
Route sources are discovered/parsed during boot and linked as immutable RouteFile program snapshots in the Runtime Image. Normal HTTP execution does not reread the .route source on each request.
RELC also attempts native WebAssembly lowering for every route.
Native subset today
A Route can currently compile to native WASM when all of the following are true:
- it has exactly one HTTP method;
- it has no imports;
- it has no helper functions;
- the method body is exactly one
returnstatement; - that returned expression is a static JSON literal/value.
Example:
The compiler emits deterministic WASM using the RBE output ABI and stores the artifact SHA-256 in the Runtime Image. Dynamic request expressions, helpers, imports, multiple methods, and other unsupported constructs are recorded with an explicit interpreter-fallback reason.
The public HTTP dispatcher still retains the immutable REL evaluator path while native artifact dispatch coverage is expanded. “WASM artifact exists” and “this request is dispatched through WASM” are therefore intentionally documented as separate things.
Server status gate
The active Runtime Image's ServerStatus is checked for normal requests:
online— normal traffic allowed.readonly— GET/HEAD/OPTIONS allowed; mutating requests rejected.maintenance,draining,offline— normal traffic returns service-unavailable behavior.
Health/admin/maintenance control-plane routes are exempt so operators can inspect/recover the server.
Thin-route pattern
Keep reusable logic in modules:
See ../x.module/.