Middleware in Shapeless lets you add reusable logic that runs between procedure calls and handlers. It’s ideal for cross-cutting concerns like authentication, logging, and error handling.
Basic Middleware Structure
// resources/shapeless.tsconst myMiddleware = app.middleware(async ({ c, next }) => { // 1️⃣ Code that runs before the handler // ... // 2️⃣ Pass data to the next middleware or handler return await next({ customData: "value" })})
Common Use Cases
Authentication Middleware
This middleware ensures the user is authenticated before proceeding. If not authenticated, it throws an error and blocks the procedure:
// resources/shapeless.tsimport { HTTPException } from "hono/http-exception"import { shapeless } from "@shapelesss/core"interface Env { Bindings: { DATABASE_URL: string }}export const app = shapeless.init<Env>()const authMiddleware = app.middleware(async ({ c, next }) => { // Mock authentication check const isAuthenticated = true if (!isAuthenticated) { throw new HTTPException(401, { message: "Unauthorized, please sign in.", }) } // Attach user info to context for downstream handlers return await next({ user: { name: "John Doe" } })})export const publicProcedure = app.procedureexport const privateProcedure = publicProcedure.use(authMiddleware)
Now, in any privateProcedure, you can safely access the user info:
// resources/routers/post-router.tsimport { app, privateProcedure } from "../shapeless"export const postRouter = app.router({ list: privateProcedure.get(({ c, ctx }) => { // Access user info injected by middleware const { user } = ctx return c.json({ posts: [] }) }),})