I am using Next.js version 13.4.7 and have implemented a middleware that handles redirection based on a token. Now, I want to add a middleware for internationalization (i18n) using next-intl, but I am unsure how to chain multiple middlewares together in Next.js. Below is my code:
import { NextRequest, NextResponse } from 'next/server'
import jwt from 'jsonwebtoken'
import createMiddleware from 'next-intl/middleware'
const locales = ['en', 'fr']
const publicPages = ['/', '/signin', '/register']
const verifPages = ['/verifyaccount', '/resetpassword']
const i18nMiddleware = createMiddleware({
locales,
defaultLocale: 'en',
})
export const middleware = (request: NextRequest) => {
i18nMiddleware(request)
const path = request.nextUrl.pathname
const publicPathnameRegex = RegExp(
`^(/(${locales.join('|')}))?(${publicPages.join('|')})?/?$`,
'i'
)
const verifPathnameRegex = RegExp(
`^(/(${locales.join('|')}))?(${verifPages.join('|')})?/?$`,
'i'
)
const isPublicPage = publicPathnameRegex.test(path)
const isVerifPage = verifPathnameRegex.test(path)
const token = request.cookies.get('token')?.value || ''
const decodedToken: any = jwt.decode(token)
const headQuarter = decodedToken?.headQuarter
const redirectUrl = `/fr/hxoo/${headQuarter}/dashboard`
if (isPublicPage && token && !isVerifPage) {
return NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
}
if (!isPublicPage && !token && !isVerifPage) {
return NextResponse.redirect(new URL('/signin', request.nextUrl))
}
if (!isPublicPage && token) {
const routeAccess = decodedToken?.routeAccess
const pathParts = path.split('/')
const route = `/${pathParts[3]}`
if (!routeAccess.includes(route)) {
return NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
}
}
return NextResponse.next()
}
export const config = {
matcher: [
'/((?!api|_next|.*\\..*).*)',
],
}
I would appreciate any help on how to properly chain multiple middlewares in Next.js.
Had the same issue for a project in the past and ended up creating a folder called middlewares
, in this folder each individual middleware would have their own file with a named default export like so:
import { type NextRequest, NextResponse } from "next/server";
export default function MyMiddlware(request: NextRequest) {
if (myCondition) return NextResponse.redirect(/*...*/);
return undefined;
}
If the condition was met I had a NextResponse
object returned, if not I simply returned undefined. In the middleware file I then imported all of the required middlewares and executed them sequentially like so:
import { type NextRequest, NextResponse } from "next/server";
import MyMiddlware from "middlewares/MyMiddlware";
import MyOtherMiddleware from "middlewares/MyOtherMiddlware";
// middlewares to run in the order of the array
const middlewares = [MyMiddlware, MyOtherMiddlware];
export default async function middleware(request: NextRequest) {
// if a response is returned, return it otherwise call `next()`
for (const fn of middlewares) {
const response = await fn(request);
if (response) return response;
}
return NextResponse.next();
}
As you can see in the middleware file itself I simply loop through the imported middlewares and return their result if it is not undefined otherwise I call NextResponse.next()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With