If you are familiar with creating web applications using Next.js, you may have come across a very common problem: implementing global and custom middleware to your API routes is difficult. While Next.js offers simple creation of page routes, there’s no support for easily written route-specific middleware or global middleware without adding a custom server.

The solution? Connext.js, a lightweight routing and middleware npm library for Next.js, powered by Dirext.js. As a team of open source developers, we sought to bridge the gap between Next.js and Express without adding unnecessary bulk to web applications.

When building a Next.js application to scale, there are many aspects of development that can become tedious and syntactically heavy without the ability to add global and custom middleware to your API routes. For example, authenticating a user in your application may require a large amount of functionality to verify login credentials and then send back an appropriate response. Without global and custom middleware, the developer must handle all of this logic nested in one large anonymous export default function, which at the very least will have a negative impact on the readability and comprehensibility of their code.

With Connext.js, developers are able to set up routes with similar syntax to Express.js and given the ability to implement global middleware at all API routes. Connext.js also allows developers to leverage the flexibility of chaining custom middleware functions for requests coming into their pre-defined endpoints, without needing to add an additional server.

What makes Express.js something worthy of replicating?

Express.js is a prebuilt Node.js framework that can help you in creating server-side web applications faster and smarter.

Not only is Express easy to customize and configure, with over 43,000 GitHub stars, Express is the most popular Node framework. It allows the developer to define routes of their application based on HTTP methods and URLs. Express includes various middleware modules which the developer can use to perform additional tasks on the request and response while also allowing them to define error handling middleware.

Connext.js strives to replicate Express.js characteristics of simplicity, minimalism, flexibility, scalability as well as performance, which is inherited directly from Node.js itself, in Next.js. With Connext.js, you are able to define routes in your application based on HTTP methods and URLs, just as you would in Express. Connext.js also has the flexibility to add middleware functionality at these routes, with each function having persistent access to the request and response, along with the ability to move through the middleware chain with the built in next() function.

Express.js’s next() function- now in Next.js!

The biggest technical challenge our team encountered during the development of Connext.js was replicating the out of the box functionality of the next() function. Next implicitly passes the request and response object through each function in the middleware chain and acts as the catalyst for your global error handler.

We were able to leverage the persistent lexically scoped reference data found in Javascript closure as well as asynchronous promises to keep track of the current location in the user defined middleware chain, as well as to properly move onto the correct middleware function whenever the next function was invoked.

To define a route using Connext-js, add a JavaScript file inside of Next.js’s required api folder.

├── ...

├── controllers

│ ├── global.js # required for global middleware

│ └── middleware.js # suggested for modularization of middleware

├── pages # required folder for routes in Next.js

│ └── api # required folder for API routes in Next.js

| └── route.js # create example route inside of API folder

└── ...

Inside of the route file

1. Require in Connext-js and any route specific middleware controller files 2. Create a new instantiation of Connext-js 3. Set up routes by calling one of Connext-js’s built in HTTP methods Pass the current route in as the first argument Chain any desired middleware functions in the order you want them to be invoked An anonymous middleware function can be defined at the end of the middleware chain. This function will end the request cycle. 4. You can invoke multiple HTTP methods in the same route file 5. Set your Connext-js invocation as the route files export default function

const Connext = require('Connext-js');

const middleware = require('../../controllers/middleware');



const app = Connext();



app.get('/api/exampleRoute', middleware.one, middleware.two, (req, res) => {

res.status(200).json(res.example);

});

app.post('/api/exampleRoute', middleware.three, (req, res) => {

res.status(200).json(res.example);

});

app.delete('/api/exampleRoute', middleware.four, (req, res) => {

res.status(200).json(res.example);

});



export default app;

As seen in the example code snippet above, if you are familiar with handling routes in Express.js the learning curve for implementing Connext.js in your Next.js application will be minimal. Connext.js offers seamless lightweight integration into Next.js API routes and is a sensible tool for any developer looking to implement global and route specific middleware in their application.

co-authored by Sara Powers

Connext.js is an open-source project on Github created by Geist Software Solutions. The library is available for download on npm. Please follow our team’s progress on Twitter @GeistSoftware and feel free to reach out to us regarding any issues or ideas on Github.