Repository: cdimascio/express-openapi-validator
Pull request #905 (2024-02-19 19:34:30)

Add multipart fix when does not exist any body
Context in our project we have endpoints in which there is no type of body parser involved, so req.body is always undefined for those requests. This happens because the body is not consumed on the server but is simply forwarded to another API (Our API is just a proxy to another API).

Therefore, we do not validate the content of the file in any way, we only check that the endpoint exists in the SPEC.

That said, we validate that the `multipartNested` function is only applied when the body exists so as not to generate an error of `TypeError: Cannot convert undefined or null to object`.


Patch:
diff --git a/src/middlewares/openapi.request.validator.ts b/src/middlewares/openapi.request.validator.ts
index 47748cb..3bd2065 100644
--- a/src/middlewares/openapi.request.validator.ts
+++ b/src/middlewares/openapi.request.validator.ts
@@ -204,6 +204,10 @@ export class RequestValidator {
   }
 
   private multipartNested(req, schemaBody) {
+    if (!req.body) {
+      return;
+    }
+
     Object.keys(req.body).forEach((key) => {
       const value = req.body[key];
       // TODO: Add support for oneOf, anyOf, allOf as the body schema
@@ -216,7 +220,6 @@ export class RequestValidator {
         }
       }
     });
-    return null;
   }
 
   private discriminatorValidator(req, discriminator) {


Test patch:
diff --git a/test/common/app.ts b/test/common/app.ts
index cbefea4..91c120f 100644
--- a/test/common/app.ts
+++ b/test/common/app.ts
@@ -13,19 +13,22 @@ export async function createApp(
   port = 3000,
   customRoutes = (app) => {},
   useRoutes = true,
-  apiRouter = undefined,
+  useParsers = true,
 ) {
   var app = express();
   (<any>app).basePath = '/v1';
 
-  app.use(bodyParser.json());
-  app.use(bodyParser.json({ type: 'application/*+json' }));
-  app.use(bodyParser.json({ type: 'application/*+json*' }));
+  if (useParsers) {
+    app.use(bodyParser.json());
+    app.use(bodyParser.json({ type: 'application/*+json' }));
+    app.use(bodyParser.json({ type: 'application/*+json*' }));
 
-  app.use(bodyParser.text());
-  app.use(bodyParser.text({ type: 'text/html' }));
+    app.use(bodyParser.text());
+    app.use(bodyParser.text({ type: 'text/html' }));
+
+    app.use(express.urlencoded({ extended: false }));
+  }
   app.use(logger('dev'));
-  app.use(express.urlencoded({ extended: false }));
   app.use(cookieParser());
   app.use(express.static(path.join(__dirname, 'public')));
 
diff --git a/test/multipart.spec.ts b/test/multipart.spec.ts
index 6b54952..807e375 100644
--- a/test/multipart.spec.ts
+++ b/test/multipart.spec.ts
@@ -6,7 +6,7 @@ import * as request from 'supertest';
 import { createApp } from './common/app';
 
 describe('a multipart request', () => {
-  let app = null;
+  let app;
   const fileNames = [];
   before(async () => {
     const apiSpec = path.join('test', 'resources', 'multipart.yaml');
@@ -151,3 +151,41 @@ describe('a multipart request', () => {
     });
   });
 });
+
+describe('when request does not use parsers', () => {
+  let app;
+
+  after(() => {
+    (<any>app).server.close();
+  });
+
+  before(async () => {
+    const apiSpec = path.join('test', 'resources', 'multipart.yaml');
+    app = await createApp(
+      {
+        apiSpec,
+      },
+      3004,
+      (app) =>
+        app.use(
+          `${app.basePath}`,
+          express
+            .Router()
+            .post(`/sample_7`, (req, res) => res.json('ok')),
+        ),
+      false,
+      false,
+    );
+  });
+
+
+  it('should validate that endpoint exists', async () => {
+    await request(app)
+      .post(`${app.basePath}/sample_7`)
+      .set('Content-Type', 'multipart/form-data')
+      .expect(200)
+      .then((r) => {
+        expect(r.body).to.equal('ok');
+      });
+  });
+});
diff --git a/test/nested.routes.spec.ts b/test/nested.routes.spec.ts
index b9057b6..8bb8b81 100644
--- a/test/nested.routes.spec.ts
+++ b/test/nested.routes.spec.ts
@@ -37,7 +37,6 @@ describe(packageJson.name, () => {
         })
       },
       true,
-      apiRoute
     );
   });
 
diff --git a/test/resources/multipart.yaml b/test/resources/multipart.yaml
index d473cb4..64592f8 100644
--- a/test/resources/multipart.yaml
+++ b/test/resources/multipart.yaml
@@ -119,7 +119,17 @@ paths:
       responses:
         201:
           description: Created
-          
+
+  /sample_7:
+    post:
+      description: upload a file that body is not consumed by router parsers
+      requestBody:
+        content:
+          '*/*': {}
+      responses:
+        200:
+          description: Updated
+
   # TODO add test with ImageReqBody ref to Image
 
   /range: