'Express Middleware' is just a fancy way of chaining a bunch of functions. Explained in 3 mins 😎
Tags: express, productivity, javascript, webdev
Published: 2019-09-01 16:44:19

Let's start by creating the world's simplest Express server:

```javascript
import express from "express";

const app = express();

app.get('/hello', (req, res) => {
  res.send('world'));
}
```

It creates a route `/hello` that responds a body `world`.

Now let's change the last line just a little bit by adding a 3rd param called `next`:

```javascript
app.get('/hello', (req, res, next) => {
  res.send('world'));
  next();
}
```
Congratz! 🎉🎉🎉 You've just created an Express Middleware. That simple!

# Middleware == Function with `next()`

A middleware is just a function with three params `(req, res, next)`, where `next` is a function that allows you to **chain** multiple functions. Let's see another example:

```javascript

// returns true if server time is in AM
function isMorning() {...}

app.get("/hello",
  // middleware #1
  (req, res, next) => {
    if (isMorning()) {
      res.send("morning");
    } else {
      next();
    }
  },
  // middleware #2: called when isMorning() === false
  (req, res, next) => {
    res.send("afternoon");
  }
);
```

Here we are chaining two middleware functions to handle `/hello` route. We use `next()` to pass control from the first middleware to the second.

In real-world scenarios, middlewares are useful for sharing common code among routes.

# Example 1: Require user authentication for certain routes.

Here we created a middleware that only calls `next()` when user is authenticated. The middleware is shared by two routes. Note that when user is not authenticated, we don't call `next()`, which will **stop the chain**.

```javascript
function RequireUserAuthentication(req, res, next) {
  if (req.user == null) {
    res.status("401").send("User is unauthenticated.");
  } else {
    next();
  }
}

app.get("/me/name", RequireUserAuthentication, (req, res, next) => {
  res.send(req.user.name);
});

app.get("/me/avatar", RequireUserAuthentication, (req, res, next) => {
  res.send(req.user.avatar);
});
```
What if we want to use RequireUserAuthentication on all routes instead of specific routes?

# Example 2: Require user authentication for all routes.

We can use `app.use(RequireUserAuthentication)` so the `RequireUserAuthentication` middleware is 'injected' into all routes.

One thing to note is that **middlewares are ordered**. In code below, any routes defined before `app.use(RequireUserAuthentication)` are not affected.


```javascript
// This route is not affected by RequireUserAuthentication
app.get("/home", (req, res, next) => res.send(...));

// Require user auth for all routes defined after this line.
app.use(RequireUserAuthentication);

// Routes below are user sign-in required
app.get("/me/name", (req, res, next) => {
  res.send(req.user.name);
});

app.get("/me/avatar", (req, res, next) => {
  res.send(req.user.avatar);
});
```

# Example 3: Parse JSON request body into object.

Sometimes it's useful to automatically convert request body into a JSON object, so we don't have to write this same logic for every single route:

```javascript
// Converts request body into req.body as a javascript object
function JSONParser(req, res, next) {
  if (req.headers['content-type'].startsWith('application/json')) {
    const rawBody = readStreamIntoString(req);
    req.body = JSON.parse(rawBody);
  }
  next();
}

// Apply JSONParser middleware to all routes defined after this line
app.use(JSONParser);

// Reads post name and content from req.body
app.get("/new/post", (req, res, next) => {
  const postTitle = req.body.title;
  const postContent = req.body.content;
  ...
});

// Reads username from req.body
app.get("/new/user", (req, res, next) => {
  const userName = req.body.username;
  ...
});
```
Here we created a `JSONParser` middleware that parses JSON request body into an object, and sets the object as `req.body`. Later, the object is read from route `/new/post` and any other routes defined after.

# Example 4: Configurable Middlewares

Let's go fancy here by creating a 'factory' function to return middleware functions. A function for functions 🤖

```javascript
function BodyParser(options) {
  if (options.type === "JSON") {
    return (req, res, next) => {
      if (req.headers["content-type"].startsWith("application/json")) {
        const rawBody = readStreamIntoString(req);
        req.body = JSON.parse(rawBody);
      }
      next();
    };
  } else if (options.type === "URL_ENCODED") {
    return (req, res, next) => {
      if (
        req.headers["content-type"].startsWith(
          "application/x-www-form-urlencoded"
        )
      ) {
        const rawBody = readStreamIntoString(req);
        req.body = new URLSearchParams(rawBody);
      }
      next();
    };
  }
}

app.use(BodyParser({ type: "JSON" }));
app.use(BodyParser({ type: "URL_ENCODED" }));
```
In above code, we allow passing in an `options` param to control which middleware function to return.

In fact, this is exactly what [bodyParser](https://github.com/expressjs/body-parser) does for parsing request bodies (of course with more sophisticated code).

**What are some of your middleware functions used in production? Leave a comment below to share your favorites ❤️❤️❤️!**

**Check out [getd.io](https://getd.io) and leave some feedback on what features you'd like to see next ❤️❤️❤️!**