Sling Academy
Home/Node.js/Express.js: Passing Variables Through Middleware

Express.js: Passing Variables Through Middleware

Last updated: December 28, 2023

Middleware functions are a fundamental part of Express.js, allowing developers to perform operations on the request and response objects, and end the request-response cycle or call the next middleware in the stack. One common need is to pass data between middleware functions, enabling a sort of ‘conversation’ or ‘context’ to be built up during a request’s lifecycle. In this tutorial, we’ll explore several ways to pass variables through middleware in an Express.js application.

Using req object

One of the simplest ways to pass data between middleware functions is through the req object, which represents the HTTP request. Middleware can add properties to this object to be accessed by subsequent middleware.

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

function logger(req, res, next) {
  req.requestTime = Date.now();
  next();
}

app.use(logger);

app.get('/', (req, res) => {
  res.send(`Request time: ${req.requestTime}`);
});

app.listen(3000);

Using response locals

Another way to pass data is with res.locals, an object that contains response local variables scoped to the request. This is useful for passing data to templates rendered by the response.

app.use((req, res, next) => {
  res.locals.requestTime = Date.now();
  next();
});

app.get('/', (req, res) => {
  res.render('index', { requestTime: res.locals.requestTime });
});

Passing Object References

Instead of passing individual variables, it’s often useful to pass an entire object reference. This can be done similarly to passing primitives, but it allows for a more structured and potentially encapsulated way of sharing data.

function attachData(req, res, next) {
  req.context = { requestTime: Date.now() };
  next();
}

app.use(attachData);

app.get('/', (req, res) => {
  res.send(`Request time: ${req.context.requestTime}`);
});

Error Handling Middleware

We can also pass variables through error handling middleware functions. This can help to provide more context when something goes wrong.

function errorHandler(err, req, res, next) {
  console.error(err.stack);
  req.errorContext = { error: 'InternalServerError', time: Date.now() };
  next(err);
}

function logError(req, res, next) {
  const errorContext = req.errorContext;
  console.error(errorContext);
  next();
}

app.use(errorHandler);
app.use(logError);

Advanced Scenarios

For more advanced scenarios, such as ensuring certain middleware runs before others or when using conditional middleware, passing variables can become more complex.

Here is an example using conditional middleware and closures to encapsulate the variable passing.

function conditionallyAttachData(condition) {
  return function(req, res, next) {
    if (condition(req)) {
      req.context = {...req.context, specificKey: 'someValue'};
    }
    next();
  };
}

app.use(conditionallyAttachData(req => req.path === '/special'));

Conclusion

In this tutorial, we have looked at various methods to pass variables through middleware in Express.js. While the req object and res.locals are often sufficient for many use cases, understanding how to pass entire object references and use advanced patterns can greatly enhance the flexibility and maintainability of your application.

Implementing these techniques will enable better communication between different parts of your middleware stack, helping you to build more modular and robust web applications.

Next Article: How to Integrate H2 Database with Express and Node.js

Previous Article: Using res.end() and res.send() in Express JS

Series: Node.js & Express Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates