Middleware for Next.js api routes
⚠️ This package is for projects using Next.js Pages Router. For projects using App Router see next-route-handler-pipe.
Middleware functions allows us to abstract reusable code that runs before the api handler is invoked. They have access to the req
, res
, and the next
middleware function.
- Add data to the
req
object (without TypeScript complaining!) - Reject wrong request methods
- Capture errors
- Validate body/query data
npm i next-api-route-middleware
Your middleware is a function that accepts req
, res
, and next
. It should call next()
when done, or send a response.
export type NextApiRequestWithUser = NextApiRequest & User;
export const withUser: Middleware<NextApiRequestWithUser> = async (req, res, next) => {
const authCookie = await getUserByCookie();
if (authCookie) {
req.userId = authCookie.userId;
await next();
} else {
res.status(401).send({ message: 'Invalid auth cookie.' });
}
};
3. Export the use
function. Include an array of middlewares in the order you want them to execute, along with your handler as the last item in the array.
import { use } from 'next-api-route-middleware';
const handler = async (req: NextApiRequestWithUser, res: NextApiResponse<User>) => {
res.status(200).json({ userId: req.userId });
};
export default use(captureErrors, allowMethods(['GET']), addhUser, handler);
You can add data to the req
object, and it will be available in your handler. In this example we get a userId from an http cookie, if the cookie isn't valid we return a 401.
export const addUser: Middleware<NextApiRequestWithUser> = async (req, res, next) => {
const authCookie = await getUserByCookie();
if (authCookie) {
req.userId = authCookie.userId;
await next();
} else {
res.status(401).send({ message: 'Invalid auth cookie.' });
}
};
You may find that you need to add args to a middleware. To achieve this we make use of a factory pattern. The allowMethods
function bellow accepts an array of allowed methods, and returns a middleware. We can make use of this factory by calling the function: allowMethods(['GET', 'POST'])
import { Middleware } from 'next-api-route-middleware';
export const allowMethods = (allowedMethods: string[]): Middleware => {
return async function (req, res, next) {
if (allowedMethods.includes(req.method!) || req.method == 'OPTIONS') {
await next();
} else {
res.status(405).send({ message: 'Method not allowed.' });
}
};
};
We can also perform actions with inner middleware functions. In this example we wrap the inner middleware functions in a try catch, allowing us to catch any errors that bubble up.
import { Middleware } from 'next-api-route-middleware';
export const captureErrors: Middleware = async (req, res, next) => {
try {
await next();
} catch (error) {
console.error(error);
res.status(500).send({ message: 'Server error!' });
}
};