Promise chain is never terminated if middleware aborts request
EvHaus opened this issue · comments
Describe the bug
I'm using next-api-middleware
to create a middleware that does some validation and aborts the API handler if the validation fails. This middleware never calls next()
and instead aborts the stack early and returns an error response instead. When this happens, next-api-middleware
will never resolve the main Promise chain for the API endpoint handler. This is not a problem in Next.js itself, which will happily still generate a valid HTTP response, but it's an issue when trying to unit test API endpoint handlers as the you cannot await
the handlers anymore.
To Reproduce
Minimally reproducible repo here: https://stackblitz.com/edit/nextjs-uzugkb?file=README.md
You can run that repo with npm run dev
and visit /api/hello
to see that the middleware and API route work as expected (returns an error). However, if you run the tests npm run test
you'll see that the tests timeout because the unit test code tries to await
the API handler response and it never resolves.
Expected behavior
Using a middleware that next calls next()
works fine. However, when you use a middleware that doesn't ever call next()
and instead returns a non-undefined
response, it should abort the promise chain and call finish()
in the executor. Right now it doesn't.
Additional info
Additionally, I noticed that any API handlers wrapped with middleware will no longer resolve with the value of the handler. For example:
// api/hello.js
export default function handler () {
return Promise.resolve('hello')
}
// api/hello.test.js
import handler from './hello';
import {use} from 'next-api-middleware';
// This works!
it('should resolve with the value', async () => {
const response = await handler();
expect(response).toEqual('hello');
});
// This doesn't work
it('should resolve with the value when wrapped with middleware', async () => {
const middleware = (req, res, next) => {
// A middleware that does nothing and just continues the promise chain
return next();
}
const response = await use(middleware)(handler)();
expect(response).toEqual('hello');
});
@EvHaus – Thank you for raising this! Many apologies for the delayed response. It looks like my notification settings for this project weren't configured to notify me if someone filed an issue or PR 🤦 .
I think your solution for this in the linked PR makes sense.
You might have noticed that I started converting canary
over to ES Modules a little while ago but didn't finish. Now that TypeScript 4.7 has better support for ES Modules, I plan on finishing up that conversion in the near future and releasing a major update. Once that takes place, I will gladly merge in your PR.
@htunnicliff Sounds great. Let me know if you need help rebasing the PR after your ES Module changes.
@EvHaus absolutely!
In the meantime, I can highly recommend patch-package if you want to apply your changes to any of your projects using this library.
@EvHaus I just released v2.0.0, so I'll be happy to merge in your PR once it is updated. Thank you for your patience 🙏
Fixed in #59