Repository: nestjs/swagger
Pull request #2303 (2023-02-21 11:37:22)

fix(core): error when using enum array on api-query
When you add inside of a query parameter an array of enums, the project simply crashes

## 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)
- [x] 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: https://github.com/nestjs/swagger/issues/1096


## What is the new behavior?
a full reproduction repo is available by the issue creator https://github.com/murbanowicz/nest-swagger-1096
```
//enum
export enum FooEnum {
  BAR = 'BAR',
  FOO = 'FOO',
}
//DTO class
class BuggyQueryDTO {
  @ApiProperty({
    isArray: true,
    enum: FooEnum,
    enumName: 'buggy',
  })
  public readonly foos!: FooEnum[];
}
// controller
  @Get()
  getHello(@Query() query: BuggyQueryDTO): string {
    return this.appService.getHello();
  }```
The above code will throw error on SwaggerModule.createDocument(app, options);:
```
TypeError: Cannot read property 'items'
 of undefined
    at SchemaObjectFactory.createEnumParam (/home/marek/dev/oss/bugs/enum-array-query/
node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:168:31)
    at SchemaObjectFactory.createQueryOrParamSchema (/home/marek/dev/oss/bugs/enum-arr
ay-query/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:51:25)
    at /home/marek/dev/oss/bugs/enum-array-query/node_modules/@nestjs/swagger/dist/ser
vices/schema-object-factory.js:31:29
    at Array.map (<anonymous>)
    at SchemaObjectFactory.createFromModel (/home/marek/dev/oss/bugs/enum-array-query/
node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:20:45)
    at exports.exploreApiParametersMetadata (/home/marek/dev/oss/bugs/enum-array-query
/node_modules/@nestjs/swagger/dist/explorers/api-parameters.explorer.js:33:55)
    at /home/marek/dev/oss/bugs/enum-array-query/node_modules/@nestjs/swagger/dist/swa
gger-explorer.js:73:45
    at Array.reduce (<anonymous>)
    at /home/marek/dev/oss/bugs/enum-array-query/node_modules/@nestjs/swagger/dist/swa
gger-explorer.js:72:99
    at /home/marek/dev/oss/bugs/enum-array-query/node_modules/lodash/lodash.js:13427:3
8```

## 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

My changes are based on https://github.com/nestjs/swagger/pull/1111 P/R but I don't have permissions to update and improve. We were using the code as @mksony commented with the patcher, and I've found some weird bug that in some case the enum options simply dissapeared. This version should work fine for all the cases. 



Patch:
diff --git a/lib/services/parameter-metadata-accessor.ts b/lib/services/parameter-metadata-accessor.ts
index 2af05fe1..fcbf8fca 100644
--- a/lib/services/parameter-metadata-accessor.ts
+++ b/lib/services/parameter-metadata-accessor.ts
@@ -5,7 +5,7 @@ import {
 } from '@nestjs/common/constants';
 import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
 import { isEmpty, mapValues, omitBy } from 'lodash';
-import { ParameterLocation } from '../interfaces/open-api-spec.interface';
+import { ParameterLocation, SchemaObject } from '../interfaces/open-api-spec.interface';
 import { reverseObjectKeys } from '../utils/reverse-object-keys.util';
 
 interface ParamMetadata {
@@ -19,6 +19,7 @@ export interface ParamWithTypeMetadata {
   type?: Type<unknown>;
   in?: ParameterLocation | 'body' | typeof PARAM_TOKEN_PLACEHOLDER;
   isArray?: boolean;
+  items?: SchemaObject;
   required: true;
   enum?: unknown[];
   enumName?: string;
diff --git a/lib/services/schema-object-factory.ts b/lib/services/schema-object-factory.ts
index 93999084..71ed88df 100644
--- a/lib/services/schema-object-factory.ts
+++ b/lib/services/schema-object-factory.ts
@@ -249,9 +249,13 @@ export class SchemaObjectFactory {
     if (!(enumName in schemas)) {
       const _enum = param.enum
         ? param.enum
-        : param.schema['items']
+        : param.schema ?
+        (param.schema['items']
         ? param.schema['items']['enum']
-        : param.schema['enum'];
+        : param.schema['enum'])
+        : param.isArray && param.items
+        ? param.items.enum
+        : undefined;
 
       schemas[enumName] = {
         type: param.schema?.['type'] ?? 'string',


Test patch:
diff --git a/e2e/api-spec.json b/e2e/api-spec.json
index 008435c2..2423a5ba 100644
--- a/e2e/api-spec.json
+++ b/e2e/api-spec.json
@@ -335,6 +335,17 @@
               }
             }
           },
+          {
+            "name": "letters",
+            "required": true,
+            "in": "query",
+            "schema": {
+              "type": "array",
+              "items": {
+                "$ref": "#/components/schemas/Letter"
+              }
+            }
+          },
           {
             "name": "beforeDate",
             "required": true,
@@ -513,6 +524,17 @@
               }
             }
           },
+          {
+            "name": "letters",
+            "in": "query",
+            "required": true,
+            "schema": {
+              "type": "array",
+              "items": {
+                "$ref": "#/components/schemas/Letter"
+              }
+            }
+          },
           {
             "name": "beforeDate",
             "in": "query",
@@ -1115,6 +1137,14 @@
           "enum",
           "enumArr"
         ]
+      },
+      "Letter": {
+        "type": "string",
+        "enum": [
+          "A",
+          "B",
+          "C"
+        ]
       }
     }
   },
diff --git a/e2e/src/cats/dto/pagination-query.dto.ts b/e2e/src/cats/dto/pagination-query.dto.ts
index dd9d315b..1572e871 100644
--- a/e2e/src/cats/dto/pagination-query.dto.ts
+++ b/e2e/src/cats/dto/pagination-query.dto.ts
@@ -38,7 +38,14 @@ export class PaginationQuery {
     enumName: 'LettersEnum',
     isArray: true
   })
-  enumArr: LettersEnum;
+  enumArr: LettersEnum[];
+
+  @ApiProperty({
+    enum: LettersEnum,
+    enumName: 'Letter',
+    isArray: true,
+  })
+  letters: LettersEnum[];
 
   @ApiProperty()
   beforeDate: Date;
diff --git a/test/services/schema-object-factory.spec.ts b/test/services/schema-object-factory.spec.ts
index 6222b22a..091127d5 100644
--- a/test/services/schema-object-factory.spec.ts
+++ b/test/services/schema-object-factory.spec.ts
@@ -25,6 +25,13 @@ describe('SchemaObjectFactory', () => {
       User = 'user'
     }
 
+    enum Group {
+      User = 'user',
+      Guest = 'guest',
+      Family = 'family',
+      Neighboard = 'neighboard'
+    }
+
     class CreatePersonDto {
       @ApiProperty()
       name: string;