Express.Js Middleware

Express.Js Middleware

Express.js is a minimal and flexible Node.js web application framework that provides broad features for building web and mobile applications. It is designed to make building server-side applications in Node.js easier by providing simple and expressive syntax for defining routes, handling HTTP requests and responses, and integrating with various middleware.

What is Middleware

Express Middleware is a function that has access to the request object (req), the response object(res), and the next middleware function in the application's request-response cycle. The next middleware function is commonly denoted by the variable 'next'.

Middleware functions can add functionality to the request-response cycle, authenticate users, handle errors, and perform other tasks.

Functions of Middleware

Express Middleware can perform various tasks, such as the following:

  1. Execute any code.

  2. Modify the request/response cycle.

  3. End request-response cycle.

  4. Call the next middleware function in the stack.

Elements of Middleware

The figure below shows the basic elements required in a middleware function

Elements of Express.js Middleware

  1. HTTP method for which the middleware function applies.

  2. Path (route) for which the middleware function applies.

  3. The middleware function.

  4. The HTTP request argument to the middleware function is called "req" by convention.

  5. The HTTP response argument to the middleware function is called "res" by convention.

  6. The callback argument to the middleware function is called "next" by convention.

It is important to note that if the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging. You can use res.end() to end the request-response cycle in the middleware function.

To load the middleware function, call app.use(), specifying the middleware function. You must load the middleware function in the sequential order you want it to be executed.

Types of Middleware

Express middleware is of different types:

  • Application-level Middleware

  • Route-specific Middleware

  • Error-handling Middleware

  • Third-Party Middleware

  • Built-in Middleware

Application-level Middleware

These middleware functions are bound to an instance of the express application and executed at the application level. At the application level, middleware is commonly used to perform tasks such as logging, user authentication, and error handling. Application-level middleware is defined using app.use() and is executed for every request.

Here is an example of application-level middleware. Whenever the app receives a request, it prints the message 'Hello, Middleware!' to the console.

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

// Middleware function
const simpleMiddleware = (req, res, next) => {
  console.log('Hello, Middleware!');
  next(); // Call next to pass control to the next middleware in the stack
};

// Use middleware for all routes
app.use(simpleMiddleware);

// HTTP Route handler
app.get('/', (req, res) => {
  res.send('Hello, Middleware!');
});

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

The app.use(simpleMiddleware) line ensures that this middleware is executed for all routes. The next() function is called to pass control to the next middleware in the stack.

Route-level Middleware

It works similarly to the application-level, except it is bound to an instance of express.Router(). They are middleware functions applied to specific routes or groups of routes. Route-level middleware is defined by using the router.use() methods.

An example is given below:

const express = require('express');
const app = express();
const router = express.Router()

// A middleware function with no mount path. This code is executed for every request to the router
router.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

// Route-specific middleware
const routeMiddleware = (req, res, next) => {
  console.log('This middleware is only for the /specific route.');
  next();
};

// Middleware for a specific route
router.get('/specific', routeMiddleware, (req, res) => {
  res.send('This is a special route.');
  next();
});

// Another route in the router without route-level middleware
router.get('/normal', (req, res) => {
  res.send('This is a normal route.');
});

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

Error-handling Middleware

Error-handling middleware functions are defined in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature (err, req, res, next)):

//Error handling middleware
const errorHandler = (err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
};
//Use error handling middleware
app.use(errorHandler);

Third-Party Middleware

This middleware is usually integrated into Express applications to provide additional functionality, such as authentication, compression, logging, and more. To use third-party packages for functions like parsing incoming request bodies, logging, and more in your app, you need to install the corresponding Node.js modules and then load them into your app.

An example of a third-party middleware package is Passport.js, Passport is a widely used authentication middleware that supports various authentication strategies.

Run this command in your app:

npm install passport passport-local
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const app = express();

// Configure passport with a local strategy
passport.use(new LocalStrategy(
  (username, password, done) => {
    // Your authentication logic goes here
    // Call done(null, user) if authentication succeeds
    // Call done(null, false) if authentication fails
  }
));

// Initialize passport and session support
app.use(passport.initialize());
app.use(passport.session());

// Your routes go here

const port = 3000;
app.listen(port, () => {
  console.log(`Server is running Port:${port}`);
});

Built-in Middleware

Express has a set of built-in middleware functions that are included in the framework and do not require additional installation. These middleware functions are designed to handle common tasks such as parsing incoming requests, serving static files, and handling errors.

Some examples of built-in middleware in Express are given below:

  • express.json() and express.urlencoded(): These middleware functions are used to parse incoming JSON and URL-encoded data from the request body, making it accessible in the req.body object.
const express = require('express');
const app = express();

// Parse incoming JSON requests
app.use(express.json());

// Parse incoming URL-encoded data
app.use(express.urlencoded({ extended: true }));

app.post('/api/data', (req, res) => {
  console.log(req.body); // Access parsed data from the request body
  res.send('Data received successfully.');
});

const port = 3000;
app.listen(port, () => {
  console.log(`Server is running on Port:${port}`);
});
  • express.static(): This middleware function serves static files (e.g., HTML, CSS, images) from a specified directory. In the example below, it serves files from the "public" directory.
const express = require('express');
const app = express();

// Serve static files from the "public" directory
app.use(express.static('public'));

CONCLUSION

Express.js is a versatile and efficient framework for building web applications on the Node.js platform. Express middleware, whether at the application or route level, allows you to seamlessly integrate custom functionalities, manage the request-response cycle, and enhance the security and organization of your applications. With built-in middleware and the ease of incorporating third-party packages, Express provides a powerful toolkit that simplifies the development process.

By leveraging Express.js and its middleware capabilities, it is easier to create scalable, modular, and feature-rich server-side applications.

You can read up more on Express.js middleware from the resources given below: