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:

  1. routes/_middleware.rex — security headers, request ID, view-source tool
  2. 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 http://localhost:4000/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' http://localhost:4000/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. A valid key must exist in the database.
   Seed one with: sqlite3 examples/knowledge-base/data.db "INSERT INTO kv VALUES('keys:demo','1')" */

api-key = headers.authorization

unless api-key do
  res.status = 401
  return { ok: false error: "missing_api_key" hint: "Add Authorization header. Seed a key: sqlite3 data.db \"INSERT INTO kv VALUES('keys:demo','1')\"" }
end

key-valid = db.get("keys:" + api-key)

unless key-valid do
  key-valid
  res.status = 401
  return { ok: false error: "invalid_api_key" }
end
key-valid

/* Authenticated identity — available to downstream handlers */
log.info(`authenticated: ${api-key}`)

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"

body = html`<h1>Tour: Middleware</h1>
<p class="source-link"><a href="/tour/templates">Next: Templates &rarr;</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 http://localhost:4000/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' http://localhost:4000/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'>&larr; Routing</a> &middot; <a href='/tour/templates'>Templates &rarr;</a>"
})