cdimascio / express-openapi-validator

🦋 Auto-validates api requests, responses, and securities using ExpressJS and an OpenAPI 3.x specification
MIT License
920 stars 211 forks source link

Support ESM import of handler module in default resolver #922

Closed mdmower-csnw closed 2 months ago

mdmower-csnw commented 6 months ago

Make the default request handler resolver work in ESM projects by allowing a URL value for options.operationHandlers. If a URL is passed, then a dynamic import will be used to load handler modules. If a string is passed, then require() will be used.

Existing projects should not be adversely affected by this change. The assignment of a URL value to options.operationHandlers would be the indicator that a user wants to opt-in to this new import handling.

Fixes #660 Fixes #838

Notice

Because this project uses moduleResolution:node in tsconfig.json, it's not possible to write async import(...) directly in code. It has to be obscured so that the compiler does not replace it with require(). Hence, there is a very obvious HACK! in this PR that obscures import() via Function('x', 'return import(x)') (it's very similar to eval('import(...)')).

This hack will probably sink this PR, but I figured I'd post it at least as a proof of concept. Ideally, the module resolution for tsconfig would be updated to Node16, but that brings its own issues since resolveJsonModule:true would no longer work. Fix one issue, introduce another...

Usage example

import {fileURLToPath, pathToFileURL} from 'node:url';
import path from 'node:path';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const handlersPath = path.join(__dirname, '../path/to/my-routes');

const eov = OpenApiValidator.middleware({
  operationHandlers: pathToFileURL(handlersPath),
  // <rest of configuration>
});
app.use(eov);

When defining x-eov-operation-handler in schemas, include the file extension on the module name. For example:

{
  "get": {
    "summary": "Get thing",
    "x-eov-operation-id": "getThing",
    "x-eov-operation-handler": "things.js", // <-- include file extension
    "responses": {
cdimascio commented 5 months ago

921 is now merged. please resolve conflicts and will get this in as well

mdmower-csnw commented 5 months ago

Usage instructions could be incorporated into https://github.com/cdimascio/express-openapi-validator/tree/master/examples/5-custom-operation-resolver, but maybe the name should change to 5-operation-resolvers with two sections: esm tips and custom resolvers? Then the link in the documentation on operation handlers would need to be updated as well. Let me know how I can help.