Published: August 20 2021

Next.js API - Add Middleware to API Routes Example & Tutorial

Tutorial built with Next.js 11.1.0

This is a quick post to show how to add middleware to the request pipeline of a Next.js API so it supports similar functionality to ExpressJS.

The code snippets in this post are taken from a Next.js auth tutorial I posted recently, to see the code running as part of a larger project go to Next.js 11 - User Registration and Login Tutorial with Example App.

API Routing in Next.js

In Next.js the /pages/api folder contains all api endpoints which are routed based on file name, for example the file /pages/api/users/index.js will be mapped to the route /api/users. A route handler exports a default function that accepts an HTTP request (req) and response (res) object. For more info see https://nextjs.org/docs/api-routes/introduction.


Example Next.js API Route Handler

Here's an example Next.js API route handler that returns a list of users for GET requests.

import { usersRepo } from 'helpers';

export default handler;

function handler(req, res) {
    switch (req.method) {
        case 'GET':
            return getUsers();
        default:
            return res.status(405).end(`Method ${req.method} Not Allowed`)
    }

    function getUsers() {
        const users = usersRepo.getAll();
        return res.status(200).json(users);
    }
}


Adding API Middleware to Next.js

The way to add support for middleware in Next.js is with a wrapper function that executes middleware before running the handler. It's a bit different to adding middleware in other frameworks like ExpressJS because API routes are mapped automatically by the Next.js framework.


API Handler Wrapper Function

The apiHandler() wrapper function from the example Next.js app is used by all API route handlers, it enables adding global middleware to the request pipeline by executing each middleware function before the API route handler, at the moment it includes just one middleware for validating JWT tokens. Global error handling is also implemented by executing everything within a try/catch block and passing errors to the errorHandler().

The apiHandler() function accepts a handler object that contains a method for each HTTP method that is supported by the handler (e.g. get, post, put, delete etc). If a request is received for an unsupported HTTP method a 405 Method Not Allowed response is returned.

import { errorHandler, jwtMiddleware } from 'helpers/api';

export { apiHandler };

function apiHandler(handler) {
    return async (req, res) => {
        const method = req.method.toLowerCase();

        // check handler supports HTTP method
        if (!handler[method])
            return res.status(405).end(`Method ${req.method} Not Allowed`);

        try {
            // global middleware
            await jwtMiddleware(req, res);

            // route handler
            await handler[method](req, res);
        } catch (err) {
            // global error handler
            errorHandler(err, res);
        }
    }
}


Wrapper Function Usage

This is the users index API route handler (/pages/api/users/index.js) from the example Next.js app, it's a refactored version of the above example API route handler that uses the apiHandler() wrapper function. It supports HTTP GET requests which are mapped to the getUsers() function, which returns all users without their password hash property.

The route handler supports HTTP GET requests by passing an object with a get() method to the apiHandler() function.

import { apiHandler, usersRepo, omit } from 'helpers/api';

export default apiHandler({
    get: getUsers
});

function getUsers(req, res) {
    // return users without hashed passwords in the response
    const response = usersRepo.getAll().map(x => omit(x, 'hash'));
    return res.status(200).json(response);
}


Example JWT Middleware for Next.js

The JWT middleware from the example Next.js app uses the express-jwt library to validate JWT tokens in requests sent to protected API routes, the middleware is added to the request pipeline in the API handler wrapper function.

The function returns a promisified version of the middleware so the wrapper function can await the middleware before executing the route handler.

const expressJwt = require('express-jwt');
const util = require('util');
import getConfig from 'next/config';

const { serverRuntimeConfig } = getConfig();

export { jwtMiddleware };

function jwtMiddleware(req, res) {
    const middleware = expressJwt({ secret: serverRuntimeConfig.secret, algorithms: ['HS256'] }).unless({
        path: [
            // public routes that don't require authentication
            '/api/users/register',
            '/api/users/authenticate'
        ]
    });

    return util.promisify(middleware)(req, res);
}

 


Need Some NextJS Help?

Search fiverr for freelance NextJS developers.


Follow me for updates

On Twitter or RSS.


When I'm not coding...

Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!


Comments


Supported by