Middleware
Some routes require checks before they can be accessed, such as verifying that a user is logged in before loading a dashboard.
Middleware runs during navigation. It can inspect the destination and current route, and can redirect to another path.
Creating Middleware
Create middleware with defineRouterMiddleware. It accepts a function that runs before navigation:
import { defineRouterMiddleware } from 'retend/router'; // A simple middleware that just logs where the user is going const loggingMiddleware = defineRouterMiddleware((details) => { console.log(`User is going to: ${details.to.path}`); });
The details object passed to your function contains two important properties:
to: Information about where the user is trying to go.from: Information about the current page they are leaving.
Protecting Routes (Redirects)
A common use for middleware is authentication. If a user requests a protected route without an active session, return a redirect to the login page:
import { defineRouterMiddleware, redirect } from 'retend/router'; const authMiddleware = defineRouterMiddleware((details) => { // Check if they are trying to access an admin area if (details.to.path.startsWith('/admin')) { const isLoggedIn = checkUserSession(); // Your own logic if (!isLoggedIn) { // Stop the navigation and go to the login page instead return redirect('/login'); } } // If you don't return anything, the navigation continues normally });
When middleware returns redirect(), Retend cancels the original navigation and starts navigation to the redirect path.
Asynchronous Checks
When access depends on a server check, such as session-token verification, define the middleware function as async:
import { defineRouterMiddleware, redirect } from 'retend/router'; const permissionMiddleware = defineRouterMiddleware(async (details) => { if (details.to.path.startsWith('/account')) { // Wait for the server to verify the token const hasAccess = await verifyTokenWithServer(); if (!hasAccess) { return redirect('/access-denied'); } } });
Retend waits for the Promise to settle before completing the navigation.
Using Multiple Middlewares
A Router can use multiple middleware functions. They run in the order listed. If one returns a redirect, subsequent middleware is not run for that navigation.
import { Router } from 'retend/router'; const router = new Router({ routes: myRoutes, middlewares: [ loggingMiddleware, // Runs 1st: logs the attempt authMiddleware, // Runs 2nd: checks if logged in permissionMiddleware, // Runs 3rd: checks specific permissions ], });
Separate concerns by assigning each check to its own middleware function. For example, logging middleware can run independently of authentication middleware.