swagger-api / swagger-core

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API
http://swagger.io
Apache License 2.0
7.39k stars 2.18k forks source link

Maps that use enums as keys don't explicitly declare them in the resulting swagger def. #3818

Open joaonatalio opened 3 years ago

joaonatalio commented 3 years ago

Bug Description

In some parts of my API I have Maps that use enums as keys, such as uploadedLanguages example below:

@Schema(name = "DocumentUploads", description = "Model that aggregates document metadata by uploaded languages")
data class DocumentUploads(var metadata: DocumentMetadata,
var uploadedLanguages: Map<MimeType, Set<LanguageCode>>)

@Schema(name = "MimeType", description = "Type of currently supported file types on Seller Center.", enumAsRef = true)
enum class MimeType(val mediaType: MediaType) {
    PDF(MediaType.APPLICATION_PDF), HTML(MediaType(MediaType.APPLICATION_XHTML_XML, Charsets.UTF_8));
}

This generates the default "Map" spec where keys are not known and can vary.

"DocumentUploads": {
    "type": "object",
    "properties": {
        "metadata": {
            "$ref": "#/components/schemas/DocumentMetadata"
        },
        "uploadedLanguages": {
            "type": "object",
            "additionalProperties": {
                "uniqueItems": true,
                "type": "array",
                "items": {
                    "$ref": "#/components/schemas/LanguageCode"
                }
            }
        }
    },
    "description": "Model that aggregates document metadata by uploaded languages"
}

However, since I need the resulting definition to explicitly declare possible keys as properties, I had to resort to this hack where I declare a fake swagger object with explicit properties. This is really bad since it's hacky, hard to maintain and actually forces the required array in the resulting definition which could lead to some issues if I reuse this object as a payload input for the API.

@Schema(name = "DocumentUploads", description = "Model that aggregates document metadata by uploaded languages")
data class DocumentUploads(var metadata: DocumentMetadata,
                           @field:Schema(implementation = LanguagesByMimeType::class) var uploadedLanguages: Map<MimeType, Set<LanguageCode>>)

// Dummy object only used by springdoc.
@Schema(name = "LanguagesByMimeType", description = "Shows languages by mime type")
data class LanguagesByMimeType(@field:Schema(name="PDF", nullable = false, required = false) var pdf: Set<LanguageCode>,
                               @field:Schema(name="HTML", nullable = false, required = false)var html: Set<LanguageCode>)

Resulting in:

"DocumentUploads": {
    "required": ["metadata", "uploadedLanguages"],
    "type": "object",
    "properties": {
        "metadata": {
            "$ref": "#/components/schemas/DocumentMetadata"
        },
        "uploadedLanguages": {
            "$ref": "#/components/schemas/LanguagesByMimeType"
        }
    },
    "description": "Model that aggregates document metadata by uploaded languages"
}

"LanguagesByMimeType": {
    "required": ["HTML", "PDF"],
    "type": "object",
    "properties": {
        "PDF": {
            "uniqueItems": true,
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/LanguageCode"
            }
        },
        "HTML": {
            "uniqueItems": true,
            "type": "array",
            "items": {
                "$ref": "#/components/schemas/LanguageCode"
            }
        }
    },
    "description": "Shows languages by mime type"
}

As a side note, this hack also has a bug. If I declare properties as upper-case as expected by the enum (eg. var PDF: Set<LanguageCode>) the resulting definition duplicates properties for some reason - camelcase and uppercase.

Proposed Solution

I would like to propose an alternative to handle such situations. It's understandable that springdoc can't automatically inspect map keys and determine if they're enums. But we could similarly help springdoc lib in figuring this part out via this sample property in @Schema:

@Schema(name = "DocumentUploads", description = "Model that aggregates document metadata by uploaded languages")
data class DocumentUploads(var metadata: DocumentMetadata,
                           @field:Schema(enumMap=true) var uploadedLanguages: Map<MimeType, Set<LanguageCode>>)

Resulting in:

"DocumentUploads": {
    "required": ["metadata", "uploadedLanguages"],
    "type": "object",
    "properties": {
        "metadata": {
            "$ref": "#/components/schemas/DocumentMetadata"
        },
        "uploadedLanguages": {
                "type": "object",
            "properties": {
                    "PDF": {
                        "uniqueItems": true,
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/LanguageCode"
                        }
                    },
                    "HTML": {
                        "uniqueItems": true,
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/LanguageCode"
                        }
                    }
                }
        }
    },
    "description": "Model that aggregates document metadata by uploaded languages"
}

The enumMap flag that provides this hint could be using in conjunction with requiredProperties for handling some requirements of the resulting object (eg. imagine you use this map payload as an input and you always expect "PDF" to be present in the map).

joaonatalio commented 3 years ago

bump

Ademord commented 3 years ago

any updates on this?

JayAhn2 commented 2 years ago

any update?

MonDeveloper commented 2 years ago

We also are getting into this. Please SWAGGER TEAM, the issue has been properly reported, give us our daily portion of hope :-)

KetelsenKent commented 1 year ago

Will we get this in 2023?

pic-Nick commented 1 year ago

Any chance to get it in 2024?

AlehGalo commented 1 week ago

Please let us know if it's being fixed or not.