Creating Custom Middleware in Node.js

Explore techniques for developing reusable middleware components to streamline request processing in your Node.js applications.

0 likes
40 views

Rule Content

---
title: Creating Custom Middleware in Node.js
description: Explore techniques for developing reusable middleware components to streamline request processing in your Node.js applications.
category: Node.js Cursor Rules
---

# Creating Custom Middleware in Node.js

## Context
- Applicable when developing middleware functions in Node.js applications.
- Assumes familiarity with Express.js or similar frameworks.

## Requirements
- **Single Responsibility Principle**: Ensure each middleware function performs a specific task to enhance maintainability and reusability.
- **Proper Error Handling**: Implement centralized error-handling middleware to manage errors effectively across the application.
- **Asynchronous Operations**: Utilize `async/await` syntax for asynchronous tasks to improve code readability and maintainability.
- **Middleware Order**: Arrange middleware functions in a logical sequence, placing critical operations like authentication and rate limiting early in the chain.
- **Named Functions**: Use named functions for middleware to facilitate debugging and improve code clarity.
- **Avoid Inline Middleware**: Define middleware functions separately from route handlers to maintain a clear separation of concerns.

## Examples

**Good Example: Single Responsibility Middleware**

// Logger Middleware
function loggerMiddleware(req, res, next) {
  console.log('Request received:', req.url);
  next();
}

// Authentication Middleware
function authenticationMiddleware(req, res, next) {
  if (!req.isAuthenticated()) {
    return res.status(401).send('Unauthorized');
  }
  next();
}

// Usage
app.use(loggerMiddleware);
app.use(authenticationMiddleware);
**Bad Example: Multiple Responsibilities in One Middleware**

app.use((req, res, next) => {
  console.log('Request received:', req.url);
  if (!req.isAuthenticated()) {
    return res.status(401).send('Unauthorized');
  }
  next();
});
**Good Example: Centralized Error Handling**

// Error Handling Middleware
function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
}

// Usage
app.use(errorHandler);
**Good Example: Asynchronous Middleware with async/await**

// Async Middleware
async function fetchDataMiddleware(req, res, next) {
  try {
    const data = await fetchData();
    req.data = data;
    next();
  } catch (error) {
    next(error);
  }
}

// Usage
app.use(fetchDataMiddleware);
**Good Example: Proper Middleware Order**

app.use(authenticationMiddleware);
app.use(rateLimitingMiddleware);
app.use(loggerMiddleware);
app.use(responseModifierMiddleware);
**Good Example: Named Middleware Functions**

function loggerMiddleware(req, res, next) {
  console.log('Request received:', req.url);
  next();
}

app.use(loggerMiddleware);
**Bad Example: Anonymous Middleware Functions**

app.use((req, res, next) => {
  console.log('Request received:', req.url);
  next();
});
**Good Example: Separate Middleware and Route Handlers**

app.use(loggerMiddleware);

app.get('/', (req, res) => {
  res.send('Hello from Express!');
});
**Bad Example: Mixing Middleware and Route Handlers**

app.get('/', (req, res) => {
  app.use(loggerMiddleware); // Avoid using app.use() inside route handlers
  res.send('Hello from Express!');
});