Middleware

Build reusable middleware functions for cross-cutting concerns

Middleware functions allow you to execute code before route handlers, enabling cross-cutting concerns like authentication, logging, and request preprocessing.

Basic Middleware

Create middleware using the middleware helper:

import { server, middleware } from "kitojs";
 
const logger = middleware((ctx, next) => {
  const { method, url } = ctx.req;
 
  console.log(`${method} ${url}`);
  next(); // Call next to continue to the next handler
});
 
const app = server();
app.use(logger); // Apply globally
 
app.get("/", ({ res }) => {
  res.send("Hello");
});

Middleware Order

Middleware executes in the order it’s registered:

const first = middleware((ctx, next) => {
  console.log("1");
  next();
});
 
const second = middleware((ctx, next) => {
  console.log("2");
  next();
});
 
app.use(first);
app.use(second);
 
// Request will log: 1, 2

Global vs Route Middleware

Apply middleware globally or to specific routes:

const app = server();
 
// Global - runs on all routes
app.use(logger);
 
// Route-specific
app.get("/admin", [auth, logger], ({ res }) => {
  res.send("Admin panel");
});

Async Middleware

Use async/await for asynchronous operations:

const dbMiddleware = middleware(async (ctx, next) => {
  const { req, db, res } = ctx;
  
  const userId = req.header("user-id");
  
  // Fetch user from database
  const user = await db.getUser(userId);
  
  if (!user) {
    res.status(404).send("User not found");
    return;
  }
  
  // Attach user to context (see Context Extensions)
  await next();
});

Combining Middleware

Stack multiple middleware functions:

const app = server();
 
app.get(
  "/api/admin/users",
  [auth, adminCheck, logger, rateLimiter],
  ({ res }) => {
    res.json({ users: [] });
  }
);
💡 Tip

Always call next() to continue the middleware chain. Forgetting it will cause requests to hang.

ℹ️ Note

Middleware runs before validation schemas. If you need validated data, use route handlers or context extensions.