nodejsnotes

Topic 006: Different types of middleware implementation in Node.jS.

Topic 006: Different types of middleware implementation in Node.js.


What is Middleware in Node Js?

How Does Node.js Middleware Pattern Work?

What happens when the request reaches the last middleware in the chain ?

  1. The request passes through all middleware functions in the chain.

  2. If none of the middleware functions send a response back to the client (i.e., they all call the next() function to pass control to the next middleware or route handler):

What is next() ?

Middleware Chaining


1. Logging Middleware

2. Authentication Middleware

const jwt = require("jsonwebtoken");

function authenticateToken(req, res, next) {
  const token = req.header("Authorization") && req.header("Authorization").split(" ")[1];
  if (!token) return res.sendStatus(401); // Unauthorized

  jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403); // Forbidden
    req.user = user;
    next();
  });
}

module.exports = authenticateToken;

3. Error Handling Middleware

4. Body Parsing Middleware

5. CORS Middleware

6. Rate Limiting Middleware

7. Static File Serving Middleware

8. Request Validation Middleware

9. Compression Middleware

-Certainly! Compression middleware is used to reduce the size of the response body, which can help speed up web applications by reducing the amount of data that needs to be transferred over the network. In Node.js, this can be achieved using the compression middleware.

Here is an example of how to implement compression middleware in a Node.js application using Express:

Step-by-Step Implementation:

  1. Install the compression package: You need to install the compression package from npm. You can do this using the following command:

    npm install compression
    
  2. Set up the middleware in your Express application: Once the package is installed, you can use it in your Express application as shown below:

    const express = require("express");
    const compression = require("compression");
    
    const app = express();
    
    // Use compression middleware
    app.use(compression());
    
    // Example route to test compression
    app.get("/", (req, res) => {
      res.send("Hello, this is a compressed response!");
    });
    
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server is running on port ${PORT}`);
    });
    

Explanation:

Additional Configuration (Optional):

You can configure the compression middleware by passing options. For example, you might want to set a threshold for compressing responses only if their size exceeds a certain number of bytes.

app.use(
  compression({
    threshold: 1024, // Compress responses only if their size is > 1KB
  })
);

10. Query Parsing Middleware

Query string parsers are middleware functions in Node.js applications, particularly in frameworks like Express, used to parse and validate query parameters attached to the URL. These parameters are typically appended to the end of a URL after a question mark (?) and are key-value pairs separated by ampersands (&).

The query string parser middleware parses these parameters from the URL and makes them available to your application’s route handlers. Additionally, you can implement validation logic within the middleware to ensure that the query parameters meet certain criteria or constraints.

Here’s an example of how to implement a query string parser middleware with validation using Express:

const express = require("express");
const app = express();

// Query string parser middleware
const parseQuery = (req, res, next) => {
  // Assuming we expect a 'name' parameter in the query string
  const name = req.query.name;

  // Validation logic
  if (!name) {
    return res.status(400).send("Name parameter is required.");
  }

  // Optionally, you can further validate the parameter's format or values

  // Attach the parsed query parameter to the request object for easy access in route handlers
  req.parsedQuery = { name };

  // Call next to pass control to the next middleware or route handler
  next();
};

// Apply the query string parser middleware to all routes
app.use(parseQuery);

// Example route that uses the parsed query parameter
app.get("/greet", (req, res) => {
  const { name } = req.parsedQuery;
  res.send(`Hello, ${name}!`);
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

In this example:

This is a basic example, but you can extend it to handle more complex query parameters or implement additional validation logic as needed for your application.

Certainly! Here’s how you can implement each of the mentioned middleware topics with code:

11. Custom Middleware for Business Logic

Middleware for Role-Based Access Control:

const checkUserRole = (req, res, next) => {
  // Assuming user role is stored in req.user.role
  if (req.user.role !== "admin") {
    return res.status(403).send("Access denied. You are not authorized to access this resource.");
  }
  next();
};

// Applying middleware to a specific route
app.get("/admin/dashboard", checkUserRole, (req, res) => {
  res.send("Welcome to the admin dashboard.");
});

12. Request Parsing Middleware

Body Parsers:

const bodyParser = require("body-parser");

// Parsing JSON bodies
app.use(bodyParser.json());

// Parsing URL-encoded bodies
app.use(bodyParser.urlencoded({ extended: true }));

// Parsing multipart/form-data
const multer = require("multer");
const upload = multer();
app.use(upload.none());

Query String Parsers:

const parseQuery = (req, res, next) => {
  const name = req.query.name;

  if (!name) {
    return res.status(400).send("Name parameter is required.");
  }

  req.parsedQuery = { name };
  next();
};

app.use(parseQuery);

13. Logging Middleware

Using morgan for Request Logging:

const morgan = require("morgan");
app.use(morgan("combined"));

Custom Logging Middleware:

const customLogger = (req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next();
};

app.use(customLogger);

14. Validation Middleware

Using express-validator for Request Validation:

const { body, validationResult } = require("express-validator");

const validateRequest = [
  body("email").isEmail(),
  body("password").isLength({ min: 6 }),
  (req, res, next) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    next();
  },
];

app.post("/register", validateRequest, (req, res) => {
  // Register user
});

15. Security Middleware

Helmet Middleware for Setting Security Headers:

const helmet = require("helmet");
app.use(helmet());

CORS Middleware for Cross-Origin Requests:

const cors = require("cors");

const corsOptions = {
  origin: "http://example.com",
  optionsSuccessStatus: 200,
};

app.use(cors(corsOptions));

CSRF Protection:

const csrf = require("csurf");
const csrfProtection = csrf({ cookie: true });

app.get("/payment", csrfProtection, (req, res) => {
  // Render payment form with CSRF token
});

16. Session Management Middleware

Using express-session for Session Management:

const session = require("express-session");
const MongoStore = require("connect-mongo")(session);

app.use(
  session({
    secret: "secret",
    resave: false,
    saveUninitialized: true,
    store: new MongoStore({ url: "mongodb://localhost/sessions" }),
  })
);
var express = require("express");
var cookieParser = require("cookie-parser");

var app = express();
app.use(cookieParser());

app.get("/", function (req, res) {
  // Cookies that have not been signed
  console.log("Cookies: ", req.cookies);

  // Cookies that have been signed
  console.log("Signed Cookies: ", req.signedCookies);
});

app.listen(8080);

// curl command that sends an HTTP request with two cookies
// curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello"

This code provides examples of each middleware type with their implementation in a Node.js/Express application. You can adapt and customize them according to your specific requirements and business logic.

These are some of the middleware implementations that I have worked on in my projects, each serving a specific purpose to enhance the functionality, security, and maintainability of the applications.