Middleware
A function that runs before the route and can answer, redirect or pass the request on.
Middleware wraps a request. It receives the request event and next, and either answers on its own or calls next() to continue.
import { type Middleware, redirect } from "@shadow-js/dusk/server";
/** Every page and API route under `users/` runs this first. */
export const middleware: Middleware[] = [
async (event, next) => {
if (event.cookies.get("session") === undefined) {
throw redirect("/login");
}
return next();
},
];
Switch the session on and off to see what the folder does with the request. The page is a model of the guard above, in the page.
Show the code
import { useStore } from "@shadow-js/core";
export function Guard() {
const [signedIn, setSignedIn] = useStore(false);
return (
<div class="stack">
<label>
<input
type="checkbox"
checked={signedIn()}
onChange={(event) => setSignedIn(event.currentTarget.checked)}
/>{" "}
The request has a session cookie
</label>
<p>GET /users/2</p>
<p>{signedIn() ? "middleware: next()" : 'middleware: throw redirect("/login")'}</p>
<p>{signedIn() ? "200, the page renders" : "302, Location: /login"}</p>
</div>
);
}
A _middleware.ts file covers everything under its folder, pages and API routes alike. A single route can export middleware for itself, and entry-server.ts takes a list for the whole app, outermost first.
Code after await next() runs for every outcome. A route that throws, redirects or fails validation does not reject next(): it resolves with the response the reader will get, so a header you set there is on the error page too.
Middleware runs on the server only and is removed from the browser build, so it can import anything the server can.
Next: push data to the page. More on ordering, rewrites and guards is in Routing.