SMILEY4 / ktor-swagger-ui

Kotlin Ktor plugin to generate OpenAPI and provide Swagger UI
Apache License 2.0
143 stars 26 forks source link

Schema generation for generic classes includes fully qualified class names #116

Closed bs-ondem closed 1 week ago

bs-ondem commented 3 weeks ago

When using generic Kotlin data classes as response body, the generated OpenAPI schema includes the fully qualified class name. For example, given the following generic class:

data class PagedResponse<T>(
    val data: List<T>,
    val page: Int,
    val size: Int,
    val total: Int
)

And an endpoint that returns PagedResponse<Organization>:

data class Organization(
    val id: String,
    val name: String
)
...
    get({
        request {}
        response {
            HttpStatusCode.OK to {
                description = "Test endpoint"
                body<PagedResponse<Organization>> { }
            }
        }
    })
...
}

Generates the following JSON schema:

  "com.example.plugins.PagedResponse<com.example.plugins.Organization>": {
      "type": "object",
      "properties": {
          "items": {
              "type": "array",
              "items": {
                  "$ref": "#/components/schemas/Organization"
              }
          },
          "options": {
              "$ref": "#/components/schemas/Map(String,String)"
          }
      }
  }
}

The schema should use the simplified class names, like PagedResponse<Organization>, instead of the fully qualified class names. I think the name of the type is generated here and if the rawName contains angle brackets, the functions just returns it. Is this behavior intended, or is it a bug?

Environment

Ktor Version: 2.3.12 Kotlin Version: 2.0.0 ktor-swagger-ui Version: 2.10.1

You can use my example repository to reproduce this.

SMILEY4 commented 2 weeks ago

Hi, i think this was intendet behaviour, though i cannot remember the reason for it. It was changed with version 3.x when switching to a different schema generator.

danilamactep commented 2 weeks ago

Hi, @SMILEY4 . Can you elaborate on switching to a different schema generator? Is there an example I could use? I'm on version 3.1.0 and running into a similar issue when generated ids contain angle brackets. I would like to remove the angle brackets from generated id. So, PagedResponse<Organization> would become PagedResponse.of.Organization

bs-ondem commented 2 weeks ago

Hi @SMILEY4, How can this be intended when it works properly for examples like List<String> or Map<String, String>? I also tried version 3.1.0, and it's still the same.

SMILEY4 commented 2 weeks ago

Hi @danilamactep victools/jsonschema-generator was replaced with SMILEY4/schema-kenerator in version 3.0 allowing for more customization and features specific to this plugin. You dont need to change anything, but different options to customize the final json-schemas are available now. With the new generator, you can choose between always using the full path (e.g. com.example.plugins.PagedResponse<com.example.plugins.Organization>) or only the simple names (e.g. PagedResponse<Organization>). Some information on how it integrates with ktor-swagger-ui can be found here Customizing it further is currently not possible, but would be an interesting idea that should be relativly easy to implement.

mnonnenmacher commented 2 weeks ago

@SMILEY4 Thanks for making a new JSON schema generator, as we are using kotlinx.serialization we were previously stuck with the unmaintained https://github.com/Ricky12Awesome/json-schema-serialization which required some nasty workarounds.

We could now fix this issue by using the following generator:

schemas {
    generator = { type ->
        type
            .collectSubTypes()
            .processReflection()
            .connectSubTypes()
            .handleNameAnnotation()
            .generateSwaggerSchema()
            .handleCoreAnnotations()
            .withAutoTitle(TitleType.SIMPLE) // Use the simple class names for titles.
            .compileReferencingRoot(RefType.SIMPLE) // Use the simple class names for references.
    }
}

It was a bit tricky to figure out which dependencies were required for the different functions, would be great if you could mention them in the wiki. In our case these were required:

bs-ondem commented 1 week ago

I will close this issue since it works properly with version 3.1.0.