Middleware's in NodeJS
Tags: webdev, javascript, programming, beginners
Published: 2023-12-14 05:51:29

What are Middleware ? 

Middleware refers to 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. Middleware functions can perform various tasks, such as modifying request and response objects, ending the request-response cycle, calling the next middleware function in the stack, or handling the HTTP request.

Middleware functions are central to the Express framework as they provide a way to execute code, make changes to the request and response objects, and enable the server to handle requests in a modular and flexible manner. They can be used for various purposes, such as logging, authentication, authorization, error handling, and more.

Middleware functions in Express are typically added using the `app.use()` or `router.use()` methods. These methods allow you to incorporate middleware at the application level or at the router level.

Three types : 
1. Built-In
2. Custom
3. Third Party

In the context of web development, middleware refers to software components that enable communication and data management between different software applications. In the context of Express.js, a popular web application framework for Node.js, middleware functions are essential for handling various aspects of the HTTP request-response cycle.

1. **Built-In Middleware:**
*Note: Build-in middleware does not require the next()*
   Express provides a set of built-in middleware that facilitates common tasks. Some examples include:

   - `express.json()`: This middleware parses incoming requests with JSON payloads and is typically used for handling JSON data.
   - `express.urlencoded()`: This middleware parses incoming requests with URL-encoded payloads and is commonly used with HTML form data.
   - `express.static()`: This middleware serves static files such as images, CSS, and JavaScript files.
   - `express.Router`: This middleware enables you to create modular, mountable route handlers.

2.**Custom Middleware:**
   Custom middleware refers to functions or code written by the developer to handle specific tasks during the request-response cycle. Developers can create custom middleware functions to perform tasks such as authentication, logging, error handling, data validation, and more. Custom middleware is tailored to the specific requirements of the application being developed.

   Here is an example of custom middleware in Express:

   ```javascript
   const customMiddleware = (req, res, next) => {
     // Perform custom tasks
     console.log('Custom middleware is executing');
     next(); // Call the next middleware function
   };

   app.use(customMiddleware);
   ```

3.**Third-Party Middleware:**
   Third-party middleware are middleware components developed by external parties that can be integrated into the Express application to extend its functionality. These middleware can be used for various purposes, such as request logging, compression, authentication, session management, and more. Popular third-party middleware include:

   - `body-parser`: A middleware for parsing incoming request bodies.
   - `cors`: A middleware for enabling Cross-Origin Resource Sharing (CORS) in Express applications.
   - `helmet`: A middleware for setting various HTTP headers to improve the security of the application.

   Third-party middleware can be easily incorporated into an Express application using the `npm` package manager. For example:

   ```bash
   npm install body-parser
   ```

   ```javascript
   const bodyParser = require('body-parser');
   app.use(bodyParser.json());
   ```

By leveraging the built-in, custom, and third-party middleware, developers can enhance the functionality, security, and performance of their Express applications, making it easier to handle various aspects of the request-response cycle efficiently and effectively.

#### Complete Example of the Code with Middle-ware concept

```js
const path = require("path");
const express = require("express");
const logEvents = require("./middleware/logEvents");
const cors = require("cors");
const PORT = process.env.PORT || 3500;
const app = express();


//------Concept of MiddleWare------

// Custom Middleware

app.use((req, res, next) => {
  logEvents(`${req.method}\t${req.headers.origin}\t${req.url}`, "reqLog.txt");
  next(); //to move to the next middleware function
});

  
//Third-Party Middleware CORS Cross Origin Resource Sharing

app.use(cors());


// Built-in Middleware

//urlendoded : this middleware parses incoming requests with URL-encoded payloads
app.use(express.urlencoded({ extended: false }));
//To accept the json data we use express.json() middleware
app.use(express.json());

  
//To serve the static files, we attach the folder name in static middleware (CSS/images etc are added)

//Note here by default it is app.use('/', express.static(pathname))
//and here the first argument is the route not the file location.
app.use(express.static(path.join(__dirname, "/public")));

  

//------Concept of routing--------

//1. Getting the index.html - With Regex ^(starts with) $(ends at) |(or) (html)?(This is optional contion making html optional)

app.get("^/$|/index(.html)?", (req, res) => {
  res.sendFile(path.join(__dirname, "views", "index.html"));
});

//2. let us serve another page to another route

app.get("/new-page(.html)?", (req, res) => {
  res.sendFile(path.join(__dirname, "views", "new-page.html"));
});

//3. Let us see how redirecting works ?

app.get("/old-page(.html)?", (req, res) => {
  res.redirect(301, "/new-page"); //301 is we are manually setting to 301 redirect i.e, permanent redirect
  //because by default it sets to 302 redirect code.
});

//4. Setting up a default route, i.e, /all or /*

app.get("/*", (req, res) => {
  res.status(404).sendFile(path.join(__dirname, "views", "404.html"));
});

  
app.listen(PORT, () => console.log(`Server is running on PORT: ${PORT}`));
```

Now In this example let us create a White-list which allows CORS for only the domains we want, So how to make that? 
Consider the following code before we add the CORS middleware

```js
const whiteList = [
  "https://www.yoursite.com",
  "https://127.0.0.1:500",
  "https://localhost:3500",
];

const corsOptions = {
  origin: (origin, callback) => {
    if (whiteList.indexOf(origin) !== -1) {
      callback(null, true);
    } else {
      callback(new Error("Not Allowed by CORS"));
    }
  },
  optionsSuccessStatus: 200,
};

app.use(cors(corsOptions));
```

This will allows the CORS only on the sites which are mention in the White-list


### Difference between `app.use()` and `app.all()`
In the context of the Express.js framework for Node.js, `app.use` and `app.all` are both middleware functions used to handle incoming HTTP requests, but they serve different purposes.

1.**app.use:**
   - The `app.use` method is used to mount middleware functions in the application's request-response cycle. It is often used for handling common tasks or processing logic that applies to all routes in the application.
   - It can be used to define middleware functions for specific routes or to apply middleware globally for all routes.
   - The middleware defined with `app.use` is executed for every incoming request, regardless of the request method (GET, POST, etc.) or the request URL.

   Example:
   ```javascript
   app.use((req, res, next) => {
     console.log('This middleware will be executed for every request');
     next();
   });
   ```

2.**app.all:**
   - The `app.all` method is used to handle all HTTP methods (GET, POST, PUT, DELETE, etc.) for a specific route in the application.
   - It is typically used to define a route that applies to all HTTP methods at a particular endpoint. This means that the provided middleware will be executed regardless of the HTTP method used for the request.
   - It is useful for implementing a specific logic or handling a common task for all methods at a particular route.

   Example:
   ```javascript
   app.all('/example', (req, res, next) => {
     console.log('This middleware will be executed for all HTTP methods at /example route');
     next();
   });
   ```
   can also be used for rendering 404 page of any other url routes example :
```js
app.get("/*", (req, res) => {

  res.status(404);

  if (req.accepts("html")) {
    res.sendFile(path.join(__dirname, "views", "404.html"));
  } else if (req.accepts("json")) {
    res.json({ error: "404 not found" });
  } else {
    res.type("text").send("404 not found");
  }
});

```

In simpler words, `app.use` is used for mounting middleware globally or for specific routes, and it executes for every request, while `app.all` is used to handle all HTTP methods for a specific route and is particularly useful when you want to apply the same logic to all methods at a specific endpoint.