Using middleware in Next.js API routes.

TL;DR
Use the next-api-route-middleware package to create composable middleware functions and keep your code clean. 🧽
Middleware
Middleware functions allow us to abstract reusable code that runs before the handler is invoked. They have access to the req
, res
, and the next
middleware function. Unfortunately Next doesn’t include a way to use API middleware (don’t confuse API middleware with Next.js’ edge middleware), so I wrote this small library: next-api-route-middleware.
Example uses:
- Inspect cookies
- Add data to the
req
object - Reject unaccepted request methods
- Capture errors
- Validate body/query data
Getting started
Install: npm i next-api-route-middleware
Next, create a middleware function. A middleware function accepts req
, res
, and next
. It should call next()
when done, or send a response.
Last step is to utilize the use
function to compose your middleware
export default use(captureErrors, handler);
Example middleware functions
Add to req middleware
Let’s create a middleware function that adds a new property to the req
. This function will parse an HTTP cookie to get the user data, and then either add the user data to the req
, or return a 401 error if there isn’t a valid cookie.
Nice, now our handler has access to req.user
. Notice that the middleware calls next()
when it’s done, unless there is an error in which case it sends a response. The library code checks for res.headersSent
and will stop executing the middleware if it detects a response has been sent.
Accepted methods middleware
This middleware simply checks the request method and returns an error if it’s not an expected method for the handler. Because allowMethods
needs to accept an argument (an array of allowed methods), we make use of a factory pattern. Calling allowMethods
will return a middleware with the allowed methods array injected.
Capture errors
It’s important to capture any errors that could occur in your handler, and return the appropriate 500 status code. This is also a good pattern for utilizing error tracking tools like Sentry.
Because our middleware injects the next middleware (and transversely all inner middlewares), we can wrap a try…catch around all the next middlewares and catch any errors that bubble up.
Conclusion
Middleware is an awesome solution for abstracting composable functions and keeping our code squeaky clean. I hope others find the next-api-route-middleware package useful. If you do find it useful, or have ideas to improve it, I’d love to hear your feedback!
If you want to keep up with the latest in webdev make sure to follow me here and on Twitter @Kolbysisk. 🙏