nestjs/swagger

@ApiProperty - Include default value when using `enumName`

Eirmas opened this issue · 6 comments

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

When using @ApiProperty like this:

@ApiProperty({ enum: SortOrder, default: SortOrder.DESC })

It renders the OpenAPI json like this:

{
    "name": "order",
    "required": true,
    "in": "query",
    "schema": {
        "default": "DESC",
        "enum": [
            "DESC",
            "ASC"
    ],
    "type": "string"
    }
}

However, when adding a reference to the enum using enumName instead to avoid duplicate definitions like this:

@ApiProperty({ enum: SortOrder, default: SortOrder.DESC, enumName: 'SortOrder' })

It renders like this:

{
    "name": "order",
    "required": true,
    "in": "query",
    "schema": {
        "$ref": "#/components/schemas/SortOrder"
    }
}

Here we can see that the default property is lost.

Describe the solution you'd like

Here is a discussion that explains a possible solution: OAI/OpenAPI-Specification#2948

Teachability, documentation, adoption, migration strategy

No response

What is the motivation / use case for changing the behavior?

Improve user experience when using software like Postman, Swagger or similar

Would you like to create a PR for this issue?

スクリーンショット 2024-03-31 11 48 09
ref: https://swagger.io/docs/specification/using-ref/

In v3.1.0, it appears that you can define some sibling elements, but it still don't have default property.
ref: https://spec.openapis.org/oas/v3.1.0#reference-object

OAI/OpenAPI-Specification#2948
In my opinion, the example in this page is no different than the code below.

@ApiProperty({ 
  default: SortOrder.DESC,
  allOf: [
    { $ref: getSchemaPath('SortOrder') },
  ]
})

@Eirmas , you are right, but the SortOrder schema has the default added there and it is being rendered in the swagger ui as well.

@kamilmysliwiec , I am looking to contribute, Is there any priority on the issues that I can start with?

I've ended up patching @nestjs/swagger like this:

diff --git a/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js b/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js
index b5c6978..dd9883a 100644
--- a/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js
+++ b/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js
@@ -167,16 +167,16 @@ class SchemaObjectFactory {
         }
         const enumName = metadata.enumName;
         const $ref = (0, utils_1.getSchemaPath)(enumName);
-        const additionalParams = ['description', 'deprecated', 'default'];
+        const additionalParams = ['description'];
         const additionalFields = additionalParams.reduce((acc, param) => (Object.assign(Object.assign({}, acc), (metadata[param] && { [param]: metadata[param] }))), {});
         const enumType = (_a = (metadata.isArray ? metadata.items['type'] : metadata.type)) !== null && _a !== void 0 ? _a : 'string';
         schemas[enumName] = Object.assign(Object.assign({ type: enumType }, additionalFields), { enum: metadata.isArray && metadata.items
                 ? metadata.items['enum']
                 : metadata.enum });
         const _schemaObject = Object.assign(Object.assign({}, metadata), { name: metadata.name || key, type: metadata.isArray ? 'array' : 'string' });
-        const refHost = metadata.isArray ? { items: { $ref } } : { $ref };
+        const refHost = metadata.isArray ? { items: { $ref } } : { allOf: [{$ref}] };
         const paramObject = Object.assign(Object.assign({}, _schemaObject), refHost);
-        const pathsToOmit = ['enum', 'enumName', ...additionalParams];
+        const pathsToOmit = ['enum', 'enumName'];
         if (!metadata.isArray) {
             pathsToOmit.push('type');
         }

This change will wrap the $ref in an allOf as previously suggested and retain properties like description, deprecated and default as expected.

Unfortunately there's no way of documenting the enum itself, so this code copies the description from the property to the enum schema definition. This is still the original behavior.

I have same issue(#3101). actually The declaration doesn't disappear, but you can find its default in other schema declared enumName.