WEB Programming
Express.js
02-Middleware

Middleware in Express.js

Middleware in Express refers to functions that execute in the ‘middle’ of a request/response cycle, typically before a matching route handler function is executed. Middleware functions have access to the request object (req), the response object (res), and the next() function in the application's request-response cycle.

By implementing middleware, we can:

  • Modify the req (request) or res (response) objects before processing the route.
  • Redirect users or respond to requests before other routes are processed.
  • Block clients from accessing specific routes.
  • Log requests or handle logic before processing routes.
  • Respond to requests for routes that do not exist (e.g., generate "404" errors).
  • Handle exceptions that occur during route handler processing (e.g., generate "500" series errors).

Updating the req Object

We can update the req object in our middleware to include additional properties. For example, adding a log property:

app.use((req, res, next) => {
  let loggedItem = `Request from: ${req.get('user-agent')} [${new Date()}]`;
  console.log(loggedItem);
  req.log = loggedItem;
  next();
});
 
app.get('/', (req, res) => {
  res.send(`Hello - ${req.log}`);
});

Here, the middleware logs the request and adds a log property to the req object, which is then used in the route handler.


Restricting Route Access

Middleware can be used to restrict access to specific routes:

function randomDeny(req, res, next) {
  let allowed = Math.floor(Math.random() * 2); // 0 or 1
  if (allowed) {
    next();
  } else {
    res.status(403).send('Access Denied');
  }
}
 
app.get('/secure', randomDeny, (req, res) => {
  res.send('Welcome!');
});

This middleware randomly allows or denies access to the /secure route. If denied, it sends a "403 Forbidden" response.


Handling 404 Errors

We can create a custom "404" error to handle requests for unknown routes:

app.use((req, res, next) => {
  res.status(404).send("404 - We're unable to find what you're looking for.");
});

This middleware is placed after all other route handlers to ensure it only executes if no other route matches, sending a "404 Not Found" response.


Types of Middleware

Application-Level Middleware

Application-level middleware is bound to your entire application and runs with every request or only when matching a specified route.

app.use((req, res, next) => {
  console.log('Application-level middleware');
  next();
});

Router-Level Middleware

Router-level middleware works the same way as application-level middleware but is attached to a specific router instance:

const userRouter = express.Router();
 
userRouter.use((req, res, next) => {
  console.log('userRouter Middleware!');
  next();
});

Error-Handling Middleware

Error-handling middleware is defined with four parameters (err, req, res, next) and is used for handling errors in the application:

app.get('/error-test', (req, res) => {
  throw new Error('Error Test');
});
 
app.use((err, req, res, next) => {
  res.status(500).send(`500 - ${err.message}`);
});

Built-In Middleware

Express provides built-in middleware functions for common tasks:

app.use(express.static('public')); // Serve static files
 
app.use(express.json()); // Parse JSON payloads
 
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded data