Writing Custom Middleware

Build your own middleware to add reusable behavior to your app.

Syntaxfunction mw(options) { return (req, res, next) => { ... }; }

Custom middleware is just a function that takes req, res and next. You can attach data to req, check conditions, and either respond or call next().

A common pattern is a middleware factory: a function that returns a middleware, so you can configure it. The example creates a role checker you can reuse on any route.

Example

Example · javascript
function requireRole(role) {
  return (req, res, next) => {
    if (req.headers['x-role'] !== role) {
      return res.status(403).send('Forbidden');
    }
    next();
  };
}

app.get('/admin', requireRole('admin'), (req, res) => {
  res.send('Welcome, admin');
});

When to use it

  • A team writes a custom requestId middleware that generates a UUID per request and attaches it to req and to the response header for tracing.
  • A developer creates a custom middleware that checks a plan tier stored on req.user and blocks calls that exceed the rate limit for that tier.
  • A middleware reads a tenant ID from the subdomain in req.hostname and attaches the tenant's database connection to req for all downstream handlers.

More examples

Request ID middleware

Generates a UUID, attaches it to req.id, and also sets it on the response header for client-side tracing.

Example · js
const { randomUUID } = require('crypto');

function requestId(req, res, next) {
  req.id = randomUUID();
  res.setHeader('X-Request-Id', req.id);
  next();
}

app.use(requestId);
app.get('/', (req, res) => res.json({ id: req.id }));

Timing middleware

Uses the res 'finish' event to measure and log the total time taken for every request-response cycle.

Example · js
function responseTime(req, res, next) {
  const start = Date.now();
  res.on('finish', () => {
    const ms = Date.now() - start;
    console.log(`${req.method} ${req.path} — ${ms}ms`);
  });
  next();
}

app.use(responseTime);

Tenant context middleware

Extracts the subdomain from req.hostname, looks up the matching tenant config, and attaches it to req.tenant.

Example · js
const tenants = { acme: { db: 'acme_db' }, beta: { db: 'beta_db' } };

function resolveTenant(req, res, next) {
  const host = req.hostname; // e.g. acme.myapp.com
  const subdomain = host.split('.')[0];
  req.tenant = tenants[subdomain];
  if (!req.tenant) return res.status(404).json({ error: 'Unknown tenant' });
  next();
}

app.use(resolveTenant);

Discussion

  • Be the first to comment on this lesson.