Middleware in Next.js: Moving from Express
Tags: nextjs, tutorial, webdev, node
Published: 2021-02-15 19:01:59

I'm currently moving my site to Next.js from a site that used an Express backend. I'm a huge fan of Express, and one of the things I love about Express is how simple it is to implement middleware.

Middleware is a function that you can attach to routes in order for it to run before the route. In other words, it runs in "the middle." This is useful for things like checking if a user is authenticated or has the proper roles to access a route. 

These are features you would want on multiple routes, and middleware makes it easy to write the function in one place and reuse it across multiple routes (Don't Repeat Yourself). But what about Next.js–how do you implement middleware?

Well, you could [create a custom Express server](https://nextjs.org/docs/advanced-features/custom-server) to work with Next.js, but you're losing some of the benefits of creating your API the way Next.js intended. 

Instead, you can watch how I implement middleware in my Next.js application in the video below, or for those that rather read **I have a written explanation below the video**–enjoy! 😊

Code: https://github.com/hunterbecton/next-js-middleware 

{% youtube XbvnxKzVXks %}

## Before: My Express Protect Middleware

In Express I have all my routes and middleware associated with authentication inside an `authController.js` file. One of those middleware functions is the `protect` function, which you can see in the code below:

{% gist https://gist.github.com/hunterbecton/3dc3429136a2735442ea285ac329dd64 %}

This protect function would check to see if the `req` had cookies and if the `st_accessToken` cookie was present. If so, it would attach the token to the `token` variable defined at the top of the function.

If no token was present my application would return an error asking the user to log in, so the user would never reach the final route. If a token was present the function would then proceed to run some code in a `try / catch` block. 

Inside the `try` block the token would be decoded using the `jwt.verify` method from the `jsonwebtoken` package. This method is passed the token and my application's JWT secret. Once that's decoded my application has access to the user's unique ID on `decoded.id`. This user ID is then used to make a call with Mongoose to my MongoDB database: `const currentUser = await User.findById(decoded.id);`

If no user if found the application will return an error, otherwise the function will attach a `user` object on `req` based on the `currentUser` that came back from MongoDB. Last, unless an error is caught in the `catch` block, the function calls `next()`, which tells Express to move to the next route handler or middleware.

Now routes or middleware further down the chain will have access to the user object and can use it however they want. For example, my routes for Stripe will now be able to read the Stripe Customer ID from the user object that is attached to `req.user`.

This middleware is implemented in Express when I create my routes in the `userRoutes.js` file:

{% gist https://gist.github.com/hunterbecton/d6182ef26c8f191988ce221556d840a6 %}

## Now: My Next.js withProtect Middleware

In Next.js you can create your routes in a folder called `api`, which needs to be inside the `pages` folder. Then, inside your `api` folder you can create all your route handlers, nesting them inside other folders based on how you want your API to be organized. Next.js will handle creating the routes for you, so there's no need to define them like you would in Express.

For example, a `logout.js` handler inside *pages > api > users > logout* can be accessed in development from `localhost:3000/api/users/logout`. Pretty neat, right? 

However, because Next.js handles the routing for us, we can't just pass a middleware before the route is called when we define routes ourselves in Express. So now let's look at the withProtect middleware code:

{% gist https://gist.github.com/hunterbecton/a4f10c57e761da66d474a5fd24ace81b %}

Look familiar? That's because it's almost identical to the protect middleware in Express! However, there are some important things to point out. To make them easier to see, check out this code example below where I remove some of the identical code:

{% gist https://gist.github.com/hunterbecton/ff52ee426e3a86995c2ab385aa8f868f %}

You can now see how this withProtect middleware takes the handler in as an argument, then returns a function of `(req, res)`. This essentially takes over the handler for now, before it later passes it back into the original handler when `handler(req,res)` is returned.

Now with the withProtect middleware complete, it's time to implement it inside the logout route. Refer to the following code:

{% gist https://gist.github.com/hunterbecton/d0ddedcd2cecc0da538229fd14fa7422 %}

Inside the logout handler you can see that it has access to `req.user`, which is passed on by the withProtect middleware. 

So how does the logout handler get the access? Well, if you look at the bottom of the code you will see that I wrapped the exported handler with the withProtect middleware–identical to how you would do higher order components in React: `export default withProtect(handler);`.

By doing this, the withProtect middleware will run before the logout handler and give the logout handler the user object on `req.user`, unless there is an error and the middleware will return an error.

## Chaining Multiple Middlewares in Next.js

What happens if you want to add multiple middleware on a handler? Simple, you just nest it inside the other middlewares!

For example, check out this withRoles middleware:

{% gist https://gist.github.com/hunterbecton/f7a9640e53c8097542d081804a651d25 %}

This middleware takes two arguments: the original handler function and a string of possible roles that can access the route. 

Users are assigned the role of `user` in my database by default when they're created. This is important because there are some routes, like deleting a user, that I only want users with the role of `admin` to access. 

This withRoles middleware gets access to the user on `req.user` because it's nested inside the withProtect middleware. Although it doesn't make much sense to only allow admins to logout, check out this simplified example of the logout handler:

{% gist https://gist.github.com/hunterbecton/dd279c3c266e45f5617945b4dfdb448c %}

First, the withProtect middleware runs, either attaching the user object on `req.user` or returning an error. Then the withRoles middleware checks to see if the req.user.role matches 'admin'. If it does, the logout handler is then called. Otherwise, the middleware returns a response notifying the user that they do not have the proper permissions.

Nesting middleware like this can look a little weird compared to how you would implement it in Express, but once you get the hang of it the implementation in Next.js is simple.

**Found this helpful? [Subscribe to my YouTube channel](https://www.youtube.com/channel/UCvHKiUI75ytqUcN851fRR2w?sub_confirmation=1)**