Repository: nestjs/swagger
Pull request #487 (2020-01-14 11:15:05)

fix(): use unique operation id for each endpoint (class_method)
## PR Checklist
Please check if your PR fulfills the following requirements:

- [ ] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [ ] 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. -->

Operation ID == method name

Issue Number: #482 


## What is the new behavior?

Operation ID == ClassName_MethodName

## Does this PR introduce a breaking change?
```
[ ] Yes
[ ] 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 73879ab9..e43012b6 100644
--- a/lib/swagger-explorer.ts
+++ b/lib/swagger-explorer.ts
@@ -205,10 +205,17 @@ export class SwaggerExplorer {
     return {
       method: RequestMethod[requestMethod].toLowerCase(),
       path: fullPath === '' ? '/' : fullPath,
-      operationId: method.name
+      operationId: this.getOperationId(instance, method)
     };
   }
 
+  private getOperationId(instance: object, method: Function): string {
+    if (instance.constructor) {
+      return `${instance.constructor.name}_${method.name}`;
+    }
+    return method.name;
+  }
+
   private reflectControllerPath(metatype: Type<unknown>): string {
     return Reflect.getMetadata(PATH_METADATA, metatype);
   }


Test patch:
diff --git a/test/explorer/swagger-explorer.spec.ts b/test/explorer/swagger-explorer.spec.ts
index 4f70b5d9..00d6fb34 100644
--- a/test/explorer/swagger-explorer.spec.ts
+++ b/test/explorer/swagger-explorer.spec.ts
@@ -80,7 +80,7 @@ describe('SwaggerExplorer', () => {
       expect(routes.length).toEqual(2);
 
       // POST
-      expect(routes[0].root.operationId).toEqual('create');
+      expect(routes[0].root.operationId).toEqual('FooController_create');
       expect(routes[0].root.method).toEqual('post');
       expect(routes[0].root.path).toEqual('/path/foos');
       expect(routes[0].root.summary).toEqual('Create foo');
@@ -141,7 +141,7 @@ describe('SwaggerExplorer', () => {
       });
 
       // GET
-      expect(routes[1].root.operationId).toEqual('find');
+      expect(routes[1].root.operationId).toEqual('FooController_find');
       expect(routes[1].root.method).toEqual('get');
       expect(routes[1].root.path).toEqual('/path/foos/{objectId}');
       expect(routes[1].root.summary).toEqual('List all Foos');
@@ -227,7 +227,7 @@ describe('SwaggerExplorer', () => {
       expect(routes.length).toEqual(2);
 
       // POST
-      expect(routes[0].root.operationId).toEqual('create');
+      expect(routes[0].root.operationId).toEqual('FooController_create');
       expect(routes[0].root.method).toEqual('post');
       expect(routes[0].root.path).toEqual('/path/foos');
       expect(routes[0].root.summary).toEqual('Create foo');
@@ -260,7 +260,7 @@ describe('SwaggerExplorer', () => {
       });
 
       // GET
-      expect(routes[1].root.operationId).toEqual('find');
+      expect(routes[1].root.operationId).toEqual('FooController_find');
       expect(routes[1].root.method).toEqual('get');
       expect(routes[1].root.path).toEqual('/path/foos/{objectId}');
       expect(routes[1].root.summary).toEqual('List all Foos');
@@ -355,7 +355,7 @@ describe('SwaggerExplorer', () => {
       expect(routes.length).toEqual(2);
 
       // POST
-      expect(routes[0].root.operationId).toEqual('create');
+      expect(routes[0].root.operationId).toEqual('FooController_create');
       expect(routes[0].root.method).toEqual('post');
       expect(routes[0].root.path).toEqual('/path/foos');
       expect(routes[0].root.summary).toEqual('Create foo');
@@ -385,7 +385,7 @@ describe('SwaggerExplorer', () => {
       });
 
       // GET
-      expect(routes[1].root.operationId).toEqual('find');
+      expect(routes[1].root.operationId).toEqual('FooController_find');
       expect(routes[1].root.method).toEqual('get');
       expect(routes[1].root.path).toEqual('/path/foos/{objectId}');
       expect(routes[1].root.summary).toEqual('List all Foos');
@@ -438,7 +438,7 @@ describe('SwaggerExplorer', () => {
       @ApiBody({ type: CreateFoo })
       @ApiOperation({
         summary: 'Create foo',
-        operationId: 'FooController_create',
+        operationId: 'FooController_create2',
         description: 'Allows creating Foo item',
         tags: ['foo']
       })
@@ -464,7 +464,7 @@ describe('SwaggerExplorer', () => {
       @ApiQuery({ name: 'page', type: String })
       @ApiOperation({
         summary: 'List all Foos',
-        operationId: 'FooController_find'
+        operationId: 'FooController_find2'
       })
       @ApiBody({
         schema: {
@@ -496,7 +496,7 @@ describe('SwaggerExplorer', () => {
       // POST
       expect(routes[0].root.description).toEqual('Allows creating Foo item');
       expect(routes[0].root.tags).toEqual(['foo']);
-      expect(routes[0].root.operationId).toEqual('FooController_create');
+      expect(routes[0].root.operationId).toEqual('FooController_create2');
       expect(routes[0].root.parameters.length).toEqual(0);
       expect(routes[0].root.requestBody).toEqual({
         required: true,
@@ -527,7 +527,7 @@ describe('SwaggerExplorer', () => {
       });
 
       // GET
-      expect(routes[1].root.operationId).toEqual('FooController_find');
+      expect(routes[1].root.operationId).toEqual('FooController_find2');
       expect(routes[1].root.parameters.length).toEqual(2);
       expect(routes[1].root.parameters).toEqual([
         {