Tour: Middleware
Files named _middleware.rex run before every handler in their directory
and all subdirectories. They execute root-first (most general to most specific).
Middleware Chain for This Page
When you requested /tour/middleware, the server ran:
routes/_middleware.rex— security headers, request ID, view-source tool- Then this handler (
routes/tour/middleware.rex)
Check the response headers — you'll see X-Request-Id and X-Powered-By: rex-serve
added by the global middleware.
Short-Circuit
If middleware sets res.status to 400+, the chain stops and the handler never runs.
This is how auth works:
unless api-key do res.status = 401 {ok: false, error: "unauthorized"} end
Try hitting the API without credentials: curl https://rex-serve-demo.vercel.app/api/articles
Data Passing
Variables set by middleware persist into the handler. The API middleware sets
principal = api-key, which downstream handlers can read.
View-Source: A Middleware Feature
The view-source tool is implemented entirely in the global middleware. Add
X-View-Source: 1 to any request to see the Rex source:
Try: View source for this page
curl -H 'X-View-Source: 1' https://rex-serve-demo.vercel.app/tour/middleware
Global Middleware Source
/* Global middleware: security headers, request ID, and view-source tool. This runs for EVERY request — static files, API, and pages alike. */ request-id = headers.x-request-id or time.uuid() res.headers.x-request-id = request-id res.headers.x-content-type-options = "nosniff" res.headers.x-powered-by = "rex-serve" /* View-source tool: send X-View-Source header to see the .rex source for the current route. This is opt-in per project (via this middleware). */ when headers.x-view-source do /* Map the URL path back to a source file */source-path = "routes" + path + ".rex" source = fs.read(source-path) /* Try index.rex for directory paths */ unless source do source-path = "routes" + path + "/index.rex" source = fs.read(source-path) end /* Try [slug].rex pattern — read the directory for any bracket file */ when source do res.status = 418 res.headers.content-type = "text/plain; charset=utf-8" res.headers.x-source-path = source-path "// Source: " + source-path + " " + source end end
API Middleware Source
/* API middleware: key-based authentication. Protects all /api/* routes. Configure REX_SECRET_API_KEY in the environment; rex-serve exposes it to Rex as secrets.api-key. */ api-key = headers.authorization expected-key = secrets.api-key unless expected-key do res.status = 503 return { ok: false error: "api_key_not_configured" } end unless api-key do res.status = 401 return { ok: false error: "missing_api_key" hint: "Add the configured key in the Authorization header" } end unless api-key == expected-key do res.status = 401 return { ok: false error: "invalid_api_key" } end log.info("authenticated API request")
This Page's Source
/* Tour Stop 3: Middleware */ res.headers.content-type = "text/html; charset=utf-8" layout = fs.read("routes/_layouts/page.html") unless layout do status = 500 return "layout not found" end /* Read the actual middleware source to display */ global-mw = fs.read("routes/_middleware.rex") api-mw = fs.read("routes/api/_middleware.rex") self-source = fs.read("routes/tour/middleware.rex") hl-global = when global-mw do html.raw(html.highlight(global-mw)) end hl-api = when api-mw do html.raw(html.highlight(api-mw)) end hl-self = when self-source do html.raw(html.highlight(self-source)) end auth-snippet = "unless api-key do res.status = 401 {ok: false, error: \"unauthorized\"} end" /* Build example URLs against the host actually serving this page. */ base = (headers.x-forwarded-proto or "http") + "://" + (headers.host or "localhost:4000") body = html`<h1>Tour: Middleware</h1> <p class="source-link"><a href="/tour/templates">Next: Templates →</a></p> <p>Files named <code>_middleware.rex</code> run before every handler in their directory and all subdirectories. They execute root-first (most general to most specific).</p> <h2>Middleware Chain for This Page</h2> <p>When you requested <code>/tour/middleware</code>, the server ran:</p> <ol> <li><code>routes/_middleware.rex</code> — security headers, request ID, view-source tool</li> <li><em>Then</em> this handler (<code>routes/tour/middleware.rex</code>)</li> </ol> <p>Check the response headers — you'll see <code>X-Request-Id</code> and <code>X-Powered-By: rex-serve</code> added by the global middleware.</p> <h2>Short-Circuit</h2> <p>If middleware sets <code>res.status</code> to 400+, the chain stops and the handler never runs. This is how auth works:</p> <pre>${html.raw(html.highlight(auth-snippet))}</pre> <p>Try hitting the API without credentials: <code>curl ${base}/api/articles</code></p> <h2>Data Passing</h2> <p>Variables set by middleware persist into the handler. The API middleware sets <code>principal = api-key</code>, which downstream handlers can read.</p> <h2>View-Source: A Middleware Feature</h2> <p>The view-source tool is implemented entirely in the global middleware. Add <code>X-View-Source: 1</code> to any request to see the Rex source:</p> <details class="try-it"> <summary>Try: View source for this page</summary> <pre>curl -H 'X-View-Source: 1' ${base}/tour/middleware</pre> </details> <h2>Global Middleware Source</h2> <pre>${hl-global}</pre> <h2>API Middleware Source</h2> <pre>${hl-api}</pre> <h2>This Page's Source</h2> <pre>${hl-self}</pre>` template.render(layout, { title: "Middleware" body: body footer: "<a href='/tour/routing'>← Routing</a> · <a href='/tour/templates'>Templates →</a>" })