Next Js - adding a middleware — Well, everyone needs some!!
Next Js is one of the most popular upcoming frameworks in the JavaScript community. It provides an awesome, out of the box, client side routing along with a filesystem api setup. Almost all of the necessary tooling has been done. However, I recently happened to fall upon a very common requirement where the framework failed to match my expectation. If you're reading the blog, chances are, you feel the same way.
Since Next Js provides an awesome alternative to Express.js with it's file directory based routing approach, chances are, you would not want to lose that just to be able to add a middleware. By the end of this article, you should be able to have a simple higher order function that gets the job done.
After a good amount of reading and looking up documentation online, I managed to come up with a simpler solution.
Here's what a middleware is supposed to do -
- Allow the developer peek into, maybe tweak, your
req
uest andres
ponse objects - Pass the
req
andres
to the next handler - In some cases, prevent the req from going any further
Middlewares are something that express and connect have done a really good job with. In the case of express, the syntax looks something like this -
app.use((req, res, next) => {
// some logic for the middleware
next();
});
In the case of Next Js, we simply do not have the support for middlewares.
Going through multiple approaches, this is what I concluded served me best -
- Have a wrapper higher order function that can intercept request and response
- The function should be able to pass the intercepted
req
,res
objects to the api - They should be able to accept multiple combinations and orders middlewares
What I still failed to do was to figure out a way to pass it automatically to the api calls
Here's what the implementation looked like in code
const apply = (api, middlewares = []) => {
return async ( req, res ) => {
let err = false;
for (let i = 0; i < middlewares.length; i++) {
const ware = middlewares[i];
const data = await ware(req, res);
if (data && data.status === false) {
res.json(data);
err = true;
break;
}
}
if (err) {
}
await api(req, res);
}
};
The key idea behind the above implementation is to run all middlewares parallely and continually make changes to the shared req
, res
objects on the go. If any middleware faces an issue and return a negative status, the request exits immediately. This helps in security related middlewares.
That's one way to do it.
Another way to get the job done would be -
> npm i next-high-order-middleware
The NPM Package does something similar and exposes another higher order function wrapper. This allows the following code to work.
// middlewares/index.js
import logger from "./logger";
import bodyparser from "./bodyparser";
import verifyAuthToken from "./auth";
import apply from "next-high-order-middleware";
const applyBasicMiddlewares = apply([logger, bodyparser]);
const applyAuthMiddlewares = apply([logger, bodyparser, verifyAuthToken]);
export default applyAuthMiddlewares;
// next-js-project/pages/api/endpoint
import applyAuthMiddlewares from "../../middlewares";
export default applyAuthMiddlewares(async (req, res) =>{
...
})