express-openapi-validator icon indicating copy to clipboard operation
express-openapi-validator copied to clipboard

Support ESM as operation handlers

Open mahnunchik opened this issue 4 years ago • 4 comments

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

mahnunchik avatar Sep 13 '21 06:09 mahnunchik

Hi @cdimascio

There is one of pretty simple implementation: https://github.com/CoinSpace/CoinSpace/blob/fd5c229ce60b67bcf88a342209931efb1cf87b93/server/lib/esmresolver.js

mahnunchik avatar Sep 27 '21 10:09 mahnunchik

@mahnunchik thanks for the example. it looks reasonable. to help move this along, would you be up for preparing this as a PR.

cdimascio avatar Nov 27 '21 15:11 cdimascio

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.

ViniGodoy avatar Jun 13 '22 13:06 ViniGodoy

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.

ViniGodoy avatar Jan 23 '23 19:01 ViniGodoy