express-openapi-validator
express-openapi-validator copied to clipboard
Support ESM as operation handlers
Is your feature request related to a problem? Please describe.
It would be helpfull to support ECMAScript modules as operation handlers.
export default {
// the express handler implementation for ping
ping: (req, res) => res.status(200).send('pong'),
};
Describe the solution you'd like
operationHandlers: import.meta.url
Describe alternatives you've considered
https://github.com/cdimascio/express-openapi-validator/issues/575
Hi @cdimascio
There is one of pretty simple implementation: https://github.com/CoinSpace/CoinSpace/blob/fd5c229ce60b67bcf88a342209931efb1cf87b93/server/lib/esmresolver.js
@mahnunchik thanks for the example. it looks reasonable. to help move this along, would you be up for preparing this as a PR.
I've tested @mahnunchik but it does not work for a function array. In order for this to work, the resolver usage should preview the possibility of a Promise. I've tried by modifying openapivalidator.js from:
router[method.toLowerCase()](path, resolver(basePath, route, context.apiDoc));
to:
Promise.resolve(resolver(basePath, route, context.apiDoc)).then(r => {
router[method.toLowerCase()](path, r);
});
Then changing @mahnunchik code to:
handlersCache[cacheKey] = import(modulePath).then(module => {
if (!module[oId]) {
// eslint-disable-next-line max-len
throw Error(`Could not find 'x-eov-operation-handler' with id ${oId} in module '${baseName}'. Make sure operation '${oId}' defined in your API spec exists as a handler function in '${baseName}'.`);
}
return module[oId];
}
).catch(next);
And finally just returning handlersCache[cacheKey] in the resolver function. Although it take a little extra time for the routes to work in the server, it allowed me to use an array with middlewares, just like I was already used to.
Just came back to say that I discovered that @mahnunchik implementation fails on Windows. In order to fix it, just add a "file://" in the import at line 24:
const modulePath = "file://" + path.join(handlersPath, `${baseName}.mjs`);
cache[cacheKey] = import(modulePath);
But the library should really support this properly, considering async imports properly.