openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[REQ] [kotlin-client] Support Enum Fallback Values

Open thejeff77 opened this issue 3 years ago • 4 comments

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

When an unknown value of a string pops up to a generated kotlin client, the serialization fails.

A conversation on the general spec is here, but is ongoing.

Various clients have implemented this for reliability sakes. Eg for:

I'm requesting that this be supported for the kotlin generator, which has no such config option

There may be a way to use it, however it is not documented and I'm unable to get it to work.

Describe the solution you'd like

Add an option to allow enum parsing similar to the 3 mentioned above not to fail when finding unknown values. See other client implementations & copy your ideal solution.

Describe alternatives you've considered

A modification to the OpenApi Specification is ongoing in consideration, but the preferred approach is still to have specific clients handle the use case.

Additional context

N/A

thejeff77 avatar Jul 21 '22 16:07 thejeff77

+1 to the current enum approach not being extensible enough. I'm not sure where is best to have this discussion (OpenAPI-Specification or openapi-generator), but I think that the generated clients should have support for growable-enums without data loss. I offered a potential solution in the thread you linked: https://github.com/OAI/OpenAPI-Specification/issues/1552#issuecomment-1217145382.

Bennett-Lynch avatar Aug 16 '22 20:08 Bennett-Lynch

plus one! bump bump

loran-steinberger avatar Aug 23 '22 19:08 loran-steinberger

Here is a helpful (but not perfect) workaround for Kotlin users:

  1. Expose your enum-like properties strictly as strings
  2. Declare a corresponding enum in your schema (but don't use it in any actual operations)
  3. In your application, declare an extension property that will attempt to convert the string value to the code-generated enum.

Schema definitions:

...
  schemas:
    SomeInput:
      type: object
      properties:
        color:
          type: string
    Color:
      type: string
      enum:
        - Red
        - Green
        - Blue
...

Extension property:

/**
 * Attempt to return [SomeInput.color] as one of the known [Color] enum values, or `null` if
 * no matching enum could be found.
 */
val SomeInput.colorEnum: Color?
    get() = enumValueOfLenient(color)

Like Kotlin's enumValueOf but intentionally more lenient:

inline fun <reified T : Enum<*>> enumValueOfLenient(name: String?): T? {
    return if (name.isNullOrBlank()) {
        null
    } else {
        val given = alphanumeric(name)
        T::class.java.enumConstants.firstOrNull { alphanumeric(it.name).equals(given, ignoreCase = true) }
    }
}

fun alphanumeric(name: String) = name.filter { it.isLetterOrDigit() }

Bennett-Lynch avatar Aug 26 '22 22:08 Bennett-Lynch

@Bennett-Lynch this is awesome, thanks for replying and contributing to that other discussion!

For the custom method above - I think the generated code takes care of parsing. Do you know of a way to override the generated code to use your custom parsing method?

thejeff77 avatar Sep 15 '22 19:09 thejeff77

@thejeff77 It's probably possible but I don't think it should be relevant or needed here. The whole idea is to force OpenAPI Generator to treat enum-like values as strings, and then instrument your own string-to-enum logic on top of that. If you take this approach, it doesn't matter how OAG parses enums.

Bennett-Lynch avatar Sep 26 '22 20:09 Bennett-Lynch

This would be actually a great feature. The current enum approach is not flexible and prone to breaking integrations whenever the server starts to send an unknown enum in payloads. Any news on this?

AlessandroBagnoli avatar Jul 15 '23 18:07 AlessandroBagnoli

I've proposed another solution to this problem here: https://github.com/OAI/OpenAPI-Specification/issues/1552#issuecomment-1845700136

Having an existing implementation to point to is helpful for moving this forward, but is not required. I'm tagging this project since kotlin is widely used, and hopefully moving forward support of this will help the community.

thejeff77 avatar Dec 07 '23 17:12 thejeff77