Repository: nestjs/swagger (ts)

Issue:
When using enableVersioning missing requestBody in document
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current behavior

When using nestJs enableVersioning:

```
app.enableVersioning({
        defaultVersion: ['1', '2'],
        type: VersioningType.URI,
    });
```

And creating the document:

```
    const builder = new DocumentBuilder()
        .setTitle('Some API')
        .setVersion('1')
        .setDescription('This is a test swagger doc');
    const document = SwaggerModule.createDocument(app, builder.build(), {
      operationIdFactory: (controllerKey: string, methodKey: string) => methodKey,
    });

    // missing responseBody in each version
    console.log(JSON.stringify(document, null, 2));
```

requestBody is only available on the first version in the list /v1/example and NOT on /v2/example:


```
{
  "openapi": "3.0.0",
  "paths": {
    "/v1/example": {
      "post": {
        "operationId": "postHello",
        "summary": "",
        "description": "Some api operation to post hello",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HelloDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        }
      }
    },
    "/v2/example": {
      "post": {
        "operationId": "postHello",
        "summary": "",
        "description": "Some api operation to post hello",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        }
      }
    }
  },
  "info": {
    "title": "Some API",
    "description": "This is a test swagger doc",
    "version": "1",
    "contact": {}
  },
  "tags": [],
  "servers": [],
  "components": {
    "schemas": {
      "HelloDto": {
        "type": "object",
        "properties": {
          "someProperty": {
            "type": "string",
            "description": "some property",
            "example": "pm_1DkAUlB70neqlGn3zQESm7pl"
          },
          "someOtherProperty": {
            "type": "string",
            "description": "some other property",
            "example": "pm_1DkAUlB70neqlGn3zQESm7pl"
          }
        }
      }
    }
  }
}

```



### Minimum reproduction code

https://github.com/getlabs-sean/nestjs-swaggerjs-enableVersioning-issue

### Steps to reproduce

1) `yarn install`
2) `yarn nest start`
3) see document dumped in console.log

### Expected behavior

We use code that separates the openapi.json file into versions and if the requestBody is not in each endpoint path we have broken documentation. 

### Package version

^5.2.1

### NestJS version

^8.0.0

### Node.js version

_No response_

### In which operating systems have you tested?

- [X] macOS
- [ ] Windows
- [ ] Linux

### Other

_No response_

Pull request description:
fix(): missing requestBody
Closes #1946

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [x] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)


## PR Type
What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->
- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->

Issue Number: #1946 


## What is the new behavior?


## Does this PR introduce a breaking change?
- [ ] Yes
- [x] No

<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->


## Other information


Patch:
diff --git a/lib/swagger-explorer.ts b/lib/swagger-explorer.ts
index 75d7862b..1ee4a74b 100644
--- a/lib/swagger-explorer.ts
+++ b/lib/swagger-explorer.ts
@@ -27,7 +27,8 @@ import {
   mapValues,
   omit,
   omitBy,
-  pick
+  pick,
+  cloneDeep
 } from 'lodash';
 import * as pathToRegexp from 'path-to-regexp';
 import { DECORATORS } from './constants';
@@ -184,10 +185,10 @@ export class SwaggerExplorer {
 
       if (Array.isArray(methodMetadata.root)) {
         return methodMetadata.root.map((endpointMetadata: DenormalizedDoc) => {
-          endpointMetadata = {
+          endpointMetadata = cloneDeep({
             ...methodMetadata,
             root: endpointMetadata as any
-          };
+          });
           const mergedMethodMetadata = this.mergeMetadata(
             globalMetadata,
             omitBy(endpointMetadata, isEmpty)


Test patch:
diff --git a/test/explorer/swagger-explorer.spec.ts b/test/explorer/swagger-explorer.spec.ts
index 9b3e0d32..5e91b9e8 100644
--- a/test/explorer/swagger-explorer.spec.ts
+++ b/test/explorer/swagger-explorer.spec.ts
@@ -8,7 +8,7 @@ import {
   Version,
   VersioningType
 } from '@nestjs/common';
-import { VersionValue } from '@nestjs/common/interfaces';
+import { VersionValue, VERSION_NEUTRAL } from '@nestjs/common/interfaces';
 import { ApplicationConfig } from '@nestjs/core';
 import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
 import {
@@ -1349,4 +1349,79 @@ describe('SwaggerExplorer', () => {
       });
     });
   });
+
+  describe('when multiple versions are defined', () => {
+    let explorer: SwaggerExplorer;
+    let config: ApplicationConfig;
+
+    describe('and controller versions are defined', () => {
+      const CONTROLLER_MULTIPLE_VERSIONS: VersionValue = ['2', VERSION_NEUTRAL];
+
+      class BarBodyDto {
+        name: string;
+      }
+      @Controller({
+        path: 'with-multiple-version',
+        version: CONTROLLER_MULTIPLE_VERSIONS
+      })
+      class WithMultipleVersionsController {
+        @Get()
+        foo(): void {}
+
+        @Post()
+        bar(@Body() body: BarBodyDto): BarBodyDto {
+          return body;
+        }
+      }
+
+      beforeAll(() => {
+        explorer = new SwaggerExplorer(schemaObjectFactory);
+
+        config = new ApplicationConfig();
+        config.enableVersioning({
+          type: VersioningType.URI,
+          defaultVersion: VERSION_NEUTRAL
+        });
+      });
+
+      it('should use multiple versions', () => {
+        const routes = explorer.exploreController(
+          {
+            instance: new WithMultipleVersionsController(),
+            metatype: WithMultipleVersionsController
+          } as InstanceWrapper<WithMultipleVersionsController>,
+          config,
+          'modulePath',
+          'globalPrefix'
+        );
+
+        expect(routes[0].root.path).toEqual(
+          `/globalPrefix/v${
+            CONTROLLER_MULTIPLE_VERSIONS[0] as string
+          }/modulePath/with-multiple-version`
+        );
+        expect(routes[1].root.path).toEqual(
+          `/globalPrefix/modulePath/with-multiple-version`
+        );
+      });
+
+      it('should have the requestBody in each version of POST route', () => {
+        const routes = explorer.exploreController(
+          {
+            instance: new WithMultipleVersionsController(),
+            metatype: WithMultipleVersionsController
+          } as InstanceWrapper<WithMultipleVersionsController>,
+          config,
+          'modulePath',
+          'globalPrefix'
+        );
+        const postRoutes = routes.filter(
+          (route) => route.root?.method === 'post'
+        );
+
+        expect(postRoutes[0].root.requestBody).toBeDefined();
+        expect(postRoutes[1].root.requestBody).toBeDefined();
+      });
+    });
+  });
 });