nitrojs / nitro

Next Generation Server Toolkit. Create web servers with everything you need and deploy them wherever you prefer.
https://nitro.build
MIT License
6.16k stars 506 forks source link

Add option to skip middleware #2230

Open Mokkapps opened 7 months ago

Mokkapps commented 7 months ago

Describe the feature

Hi, first thanks for this amazing project 💪🏻

In our Nuxt 3 app we have a core logic that heavily relies on Nitro's server middleware. For every server route we need to check if we want to render it in Nuxt or proxy the page from another system.

A simplified example:

export default defineEventHandler((event) => {
  if (event.path.startsWith('/skip')) {
    // middleware should not run for certain paths
    return;
  }

  if (event.path === '/cart') {
    console.log('First middleware redirect to cart');
    event.node.res.writeHead(302, {
      location: '/cart-redirect',
    });
    event.node.res.end();
  }

  if (event.path === '/user') {
    console.log('First middleware redirect to user');
    event.node.res.writeHead(302, {
      location: '/user-redirect',
    });
    event.node.res.end();
  }
});

As mentioned in the docs returning anything from middleware should be avoided:

Returning anything from a middleware will close the request and should be avoided! Any returned value from middleware will be the response and further code will not be executed however this is not recommended to do!

I'm wondering why Nitro does not provide something like a next() function to be able to skip certain middleware, as it is available in other frameworks like Express.

We definitely would like to avoid using an approach that is not recommended, what alternative would be available instead using server middleware with return for our requirements?

Reproduction

https://stackblitz.com/edit/github-yplgh6?file=server%2Fmiddleware%2F01.first.ts

Additional information

manniL commented 7 months ago

I'm wondering why Nitro does not provide something like a next() function to be able to skip certain middleware, as it is available in other frameworks like Express.

You can return as you in the example. This should skip the middleware and is, AFAIK, the way to go.

Also sending redirects via middleware seems logical to me, here I wouldn't rely on the node primitives though and use sendRedirect instead.


If I am not mistaken here, this is probably something that should be better documented.

Mokkapps commented 7 months ago

I'm wondering why Nitro does not provide something like a next() function to be able to skip certain middleware, as it is available in other frameworks like Express.

You can return as you in the example. This should skip the middleware and is, AFAIK, the way to go.

Also sending redirects via middleware seems logical to me, here I wouldn't rely on the node primitives though and use sendRedirect instead.

If I am not mistaken here, this is probably something that should be better documented.

Thanks Alexander!

If this is the case, then we should definitely update the docs for Nitro & Nuxt as both mention that such returns should be avoided.

manniL commented 7 months ago

Double checked with the team - redirects, throwing errors or skipping middleware are valid cases to "return". Cases like sending back data/HTML or a proxy are not 👀

Definitely something the docs should cover!

Mokkapps commented 7 months ago

Thanks for the update! I can try to update the documentation accordingly.

Actually, we're also returning HTML in our server middleware in certain scenarios 🙈 What would be the recommended workaround?

tmsf commented 20 hours ago

we've been working with nuxt3 as well with the need of running some middlewares in some API paths, and not in others. In order to do that we've created a wrapper for defineEventHandler where we create conditionally run middlewares.

we've just publish this npm package that gives might help you with these cases:

https://www.npmjs.com/package/nitro-conditional-middleware