Reputation: 23
I am looking to chain middleware in a nextJS project, on the latest NextJS version with the stable Middleware API. Here's an example snippet of my middleware.ts
file.
Both of these will return a NextResponse
object, how can I go about chaining them so the cookies are added first then passed along to find redirects?
I suppose I'll have to extend the API of the second middleware to take in the response and use it's contents or pass it along. Does anyone have a good example for how to go about this?
export const middleware = (req: NextRequest): NextResponse | undefined => {
addCookieMiddleware(req);
findRedirectsMiddleware(req);
// How to return a singular NextResponse object with the cookie attached and the correct URL to redirect?
}
Upvotes: 2
Views: 4228
Reputation: 1700
I'm trying to chain as well.
The docs say you can chain https://nextjs.org/docs/api-reference/next/server#static-methods
next() - Returns a NextResponse that will continue the middleware chain
Here is the source code for v12.2.2 (current at the time of writing) https://github.com/vercel/next.js/blob/689626c6a4d509fe04aaf82c9971a5928669bcf4/packages/next/server/web/spec-extension/response.ts#L64
static next(init?: ResponseInit) {
const headers = new Headers(init?.headers)
headers.set('x-middleware-next', '1')
return new NextResponse(null, { ...init, headers })
}
If it does chain, I think it has to do something with the x-middleware-next
header it is setting. I looked through the source code and I still could not determine how to chain.
The other interesting thing is next()
returns a new NextResponse
,but, next()
is a static method.
Since next()
is static, you cannot call twice.
This does not work, response
will be undefined.
const response = NextResponse.next()
response.next({
headers: {
'a-test': Math.random().toString(),
},
})
What I'm doing for now:
You set cookies by calling next()
and using the public cookie property and use Map
operations.
const response = NextResponse.next()
response.cookies.set('a-test', Math.random().toString())
You set headers by calling next()
and passing in an object with a headers
object within.
const response = NextResponse
response.next({
headers: {
'a-test': Math.random().toString(),
},
})
I first thought was to use const response = new NextResponse
but that did not work, response
would always be undefined. You have to use const response = NextResponse
Since you can only call next()
once, the best thing I could do was call the headers function first where calling next()
is required, and then calling the function that sets the cookies.
// middleware.js
import { NextResponse } from 'next/server'
const setHeaders = (response) => {
return response.next({
headers: {
'a-test': Math.random().toString(),
},
}
}
const setCookies = (response) => {
response.cookies.set('a-test', Math.random().toString())
return response
}
export async function middleware(request) {
// Limitation in config matcher, requires me to exclude here
if (request.nextUrl.pathname.startsWith('/_next')) {
return NextResponse.next()
}
let response = NextResponse
response = setHeaders(response)
response = setCookies(response)
return response
}
Hope this helps!
Upvotes: 2