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 · 6 comments
Open

Middleware Chaining utility #357

pedrocarlo opened this issue Dec 13, 2024 · 6 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

@FlurryNight
Copy link

@pedrocarlo
@haydenbleasel

I was also about to make this suggestion, but using the already open source library available for this provided by rescale.build (https://nemo.rescale.build) z4nr34l/nemo

Supporting
Dynamic segments
Functions Chaining
Shared context

Simplifying and improving overall management of middlewares.

This would be an awesome addition to this incredible project. and would help with some cleanup regarding the middlewares and allow the users to easily extend further.

Thanks,

Best Regards

@pedrocarlo
Copy link
Contributor Author

@FlurryNight just read the docs. The package is super awesome. It seems to be a good replacement for what I did. Will give it a try on my project

@FlurryNight
Copy link

@FlurryNight just read the docs. The package is super awesome. It seems to be a good replacement for what I did. Will give it a try on my project

Hey, Awesome!.

Let me know your thoughts after!

Best Regards

@haydenbleasel
Copy link
Owner

@pedrocarlo @FlurryNight this is great! now that v3 is merged, I’d love to see this implemented to handle middlewares from various packages.

would either of you be up for creating a PR?

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

3 participants