From 5c98d17c470aecf53f60d3fb3bda4005d65aa9aa Mon Sep 17 00:00:00 2001
From: Nicolas Walter Araya <nwaraya@gmail.com>
Date: Wed, 21 Feb 2024 13:04:13 -0300
Subject: [PATCH] Add multipart fix when does not exist any body (#905)

---
 src/middlewares/openapi.request.validator.ts |  5 ++-
 test/common/app.ts                           | 17 +++++----
 test/multipart.spec.ts                       | 40 +++++++++++++++++++-
 test/nested.routes.spec.ts                   |  1 -
 test/resources/multipart.yaml                | 12 +++++-
 5 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/src/middlewares/openapi.request.validator.ts b/src/middlewares/openapi.request.validator.ts
index 47748cb2..3bd2065c 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) {
diff --git a/test/common/app.ts b/test/common/app.ts
index cbefea40..91c120f0 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 6b549524..807e3759 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 b9057b6c..8bb8b81e 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 d473cb42..64592f8a 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: