Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middleware Chaining utility #357

Open
pedrocarlo opened this issue Dec 13, 2024 · 2 comments
Open

Middleware Chaining utility #357

pedrocarlo opened this issue Dec 13, 2024 · 2 comments
Labels
enhancement New feature or request

Comments

@pedrocarlo
Copy link
Contributor

Is your feature request related to a problem? Please describe.

As we add more packages that use middlewares to rewrite urls and add headers, it becomes harder to chain them together. It would be nice idea if the project had some default way to chain middlewares together.

Describe the solution you'd like
This is the code I am using in my own project to Chain Middlewares:

import "server-only";

import { NextRequest, NextResponse } from "next/server";

type Middleware = (
  request: NextRequest
) => NextResponse | Response | Promise<Response>;

export async function chainMiddleware(
  middlewares: Middleware[],
  request: NextRequest
) {
  let response: ReturnType<Middleware> = new NextResponse(
    request.body,
    request
  );
  for (const middleware of middlewares) {
    const awaitedResponse = await response;
    const url = new URL("", request.url);
    const newRequest = new NextRequest(url, awaitedResponse);
    response = middleware(newRequest);
  }
  return response;
}

And used in the code:

const middlewares = [securityHeaders, I18nMiddleware];

const Middlewares = (request: NextRequest) => {
  return chainMiddleware(middlewares, request);
};
export default authMiddleware(async (auth, request) => {
  return Middlewares(request)
}

This is my implementation, it seems to work as intended in my project, but I may be wrong. I would appreciate some input to see if this is useful or not for the project.

@pedrocarlo pedrocarlo added the enhancement New feature or request label Dec 13, 2024
@haydenbleasel
Copy link
Owner

This is very important as we start to make each package self-maintaining i.e. #332

@pedrocarlo
Copy link
Contributor Author

pedrocarlo commented Dec 13, 2024

My previous implementation was flawed, as I was not forwarding the headers to the next requests.

I settled for now on this implementation:

import "server-only";

import { type NextRequest, NextResponse } from "next/server";

type Middleware = (
  request: NextRequest
) => NextResponse | Response | Promise<Response>;

export async function chainMiddleware(
  middlewares: Middleware[],
  request: NextRequest
) {
  if (middlewares.length === 0) {
    return undefined;
  }
  let response: ReturnType<Middleware> = new NextResponse();
  const mergedHeaders = new Headers();

  for (const middleware of middlewares) {
    const currResponse = await middleware(request);
    currResponse.headers.forEach((val, key) => mergedHeaders.set(key, val));

    response = new NextResponse(null, {
      headers: mergedHeaders,
      status: currResponse.status,
      statusText: currResponse.statusText,
    });
  }

  return response;
}

I think this is good enough for now, but if you do url rewrites I have noticed some inconsistent behavior with next-international. I am most likely doing something wrong here. Eventually when each package is self-maintaining, it would be a good idea to revisit this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants