Conditional Express Middleware Skipping

2.1.3 · active · verified Wed Apr 22

express-unless is a utility library for Express.js that enables conditional execution of middleware functions. It allows developers to attach an `unless` method directly to any Express middleware, providing granular control over when that middleware should be skipped. The library currently ships as version 2.1.3 and has seen stable releases, with the latest update in April 2021. It differentiates itself by offering a fluent API for defining skip conditions based on HTTP methods, request paths (including regular expressions and path/method pairs), file extensions, or a fully custom predicate function. This approach simplifies complex conditional routing logic often found in Express applications, providing a cleaner way to apply authentication, logging, or other cross-cutting concerns selectively.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart sets up an Express application demonstrating how to apply `unless` to an authentication middleware and a logging middleware, skipping them based on paths, methods, extensions, and custom functions.

import express from 'express';
import { unless } from 'express-unless';

const app = express();
const port = 3000;

// 1. A middleware to simulate authentication
const requiresAuth = (req: express.Request, res: express.Response, next: express.NextFunction) => {
  if (req.headers.authorization === 'Bearer my-secret-token') {
    console.log('User authenticated.');
    next();
  } else {
    console.warn('Authentication failed for:', req.originalUrl);
    res.status(401).send('Unauthorized');
  }
};

// Extend the middleware with unless (type assertion for TypeScript compatibility)
(requiresAuth as any).unless = unless;

// Apply authentication to all routes UNLESS they are '/public', '/status' or OPTIONS requests
app.use(
  (requiresAuth as any).unless({
    path: ['/public', '/status'],
    method: ['OPTIONS']
  })
);

// 2. A simple logger middleware
const logger = (req: express.Request, res: express.Response, next: express.NextFunction) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
  next();
};
(logger as any).unless = unless;

// Skip logging for image files or paths including '/no-log'
app.use(logger.unless({
  ext: ['.png', '.jpg', '.gif'],
  custom: (req: express.Request) => req.originalUrl.includes('/no-log')
}));

// Public route - no auth needed
app.get('/public', (req, res) => {
  res.send('This is a public page.');
});

// Status route - no auth needed
app.get('/status', (req, res) => {
  res.send('Server is healthy.');
});

// Authenticated route
app.get('/admin', (req, res) => {
  res.send('Welcome to the admin area!');
});

// Route with images (logging skipped)
app.get('/images/test.png', (req, res) => {
  res.send('Serving image.');
});

// Route where logging is skipped via custom function
app.get('/no-log/data', (req, res) => {
  res.send('This route will not be logged.');
});

// Default route
app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Express app listening at http://localhost:${port}`);
  console.log('Try:');
  console.log('  GET http://localhost:3000/ - Authenticated');
  console.log('  GET http://localhost:3000/public - Not Authenticated');
  console.log('  GET http://localhost:3000/admin - Authenticated (requires Authorization: Bearer my-secret-token)');
  console.log('  OPTIONS http://localhost:3000/admin - Not Authenticated (skipped by method)');
  console.log('  GET http://localhost:3000/images/test.png - Logging skipped');
  console.log('  GET http://localhost:3000/no-log/data - Logging skipped by custom function');
});

view raw JSON →