Skip to main content
Middleware is a template that decides whether a request should reach a page at all. It renders nothing. Its whole output is a signal: redirect somewhere else, or carry on.
middleware/auth.slurp
A page never has to ask whether it is allowed to be rendered, so a page never has to read the request.

Selecting middleware files

Nothing about the filename or the directory makes a file middleware. The compile flag does:
The flag takes a directory relative to the scanned tree, and is repeatable:
A host embedding Slurp may keep its middleware anywhere, and the compiler has to be told which of two inverted rule sets to check a file under. It cannot guess from a path.
Without the flag, a correct middleware file fails to validate.
The same run with --middleware middleware is clean:
The failure direction is the safe one. The dangerous direction is a typo: --middleware midleware names a directory that does not exist, selects nothing, and reports the same scope violations with no hint that the flag missed. If middleware that should be checked reports request.* errors, check the spelling of the flag before the template.

What the flag selects

The middleware "auth" line in frontmatter only RECORDS a name for tooling. It does not make the file middleware, and a file with no such line is middleware if the flag selects it. Like every other frontmatter directive, a misspelling of it is skipped silently.

Checked, never emitted

Middleware produces no output file. slurp build compiles it, runs the security walk over it, and moves on:
Emitting it would be meaningless. It runs per request in the host, and writing a .html for it would put a file in dist/ that no route ever serves. Its scope rules are inverted, so the ordinary page walk reports every correct middleware file as a violation and lets a broken one through.

The scope rules are inverted

Inside middleware, exactly three path roots are readable: request, env and loop. There is no store, no cart, no product, no page data.
Outside middleware, the mirror image applies. request.* is unreadable, and both signals are compile errors:
A page that wants to know something about the request gets it the same way it gets everything else: the server puts it in the render context. A page reading cookies directly is a page whose output depends on data the host did not choose to give it.

Available language features

Middleware has the whole template language available, minus the data. In practice that means {if}, {match} and comparisons over request.*, and then a {redirect "/somewhere"} or a {next}. The language’s general limits apply. Two matter here:
There is no clock, and there are no callable functions. Date.now() parses and evaluates to null, and a comparison against null compares Equal, so a session-expiry check written that way never fires while looking like it works. Expire the cookie where it is minted and let a missing cookie be the check.
Markup in a middleware file goes nowhere. Writing <p>Hello</p> there is legal and validates clean, but the file is never emitted and {redirect} and {next} themselves render to the empty string. Middleware is a decision, not a page.

Acting on the signal

slurp build produces a static site, and a static site has no request to gate, so middleware there is checked and nothing more. The signal matters when Slurp is embedded in a server. In 0.1.0 the compiler validates the signal but does not hand it back: rendering a {redirect} yields the empty string, and there is no API that returns the target. A host that wants to act on it parses the file with parse() and walks the document for a Node::Redirect, deciding for itself in the context of a real request. Expect this seam to move before 1.0.

Next

Writing pages

File-based routing, page data, and output paths.

Project structure

Special directories, output paths, and static assets.

Errors

Every diagnostic code, including the two on this page.

CLI

Every subcommand and flag.