Hey everyone, How do you model open enumerations? ...
# server
s
Hey everyone, How do you model open enumerations? I've used a combination of sealed classes with enum, but it's not ideal. (My snippet in thread).
Copy code
sealed interface CreateChatCompletionRequestModel {
    val value: String
    
    data class Custom(override val value: String) : CreateChatCompletionRequestModel
    enum class Enum(override val value: String) : CreateChatCompletionRequestModel {
        Gpt_4_0125_Preview("gpt-4-0125-preview"),
        Gpt_4_Turbo_Preview("gpt-4-turbo-preview"),
        Gpt_4_Turbo_1106_Preview("gpt-4-1106-preview");
    }
}
Any better suggestions?
s
I would use a value class, with a companion object listing the enumerated values
s
Interesting, that does sound like a less complex solution!
I am going to try that @Sam, sounds nicer. I was also consider a sealed class with all options, but value class makes a lot of sense to me for
anyOf
which only exists out of an open enumeration.
s
I’ve found it to work really well! My use case was this:
Copy code
@JvmInline value class HttpStatus(val code: Int) {
  companion object {
    val Ok = HttpStatus(200)
    // etc
  }
}
But yours sounds very similar
It has the nice property that
HttpStatus.Ok == HttpStatus(200)
, which is the important thing
πŸ‘Œ 1
s
You lose exhaustiveness on the "fixed" part.. but for an open enumeration that doesn't really matter imho.
πŸ‘ 1
Sweet! Thanks Sam
πŸ• 1
e
If you want to retain exhaustiveness, could data objects in the interface be an option? Also converting to a sealed class makes it a bit less verbose to redeclare the field for each type? I.e. something like..
s
How do both of these play with KotlinX Serialization? πŸ€” Probably need to generate a custom serializer for both πŸ˜…
e
What do you want the json to look like? just serialize to the value string?
s
Yes, it's 100% sure that all these are Strings at that point. OpenAI seems kind-of strange, it's all open enumerations πŸ˜„ but it's done that way so they can support more, without changing the OpenAPI spec... 🀷
e
With Sams suggestion, serialization should work out of the box I believe πŸ™‚ Using data objects you would need to do something custom
s
I'm not so much concerned about a custom serializer, but just the user facing API. I've gone back -and forth between a couple of these πŸ˜…
It might also be consumed from Java, but seems it's impossible to model whilst being sane to consume from Java
c
@Sam
I’ve found it to work really well! My use case was this:
```@JvmInline value class HttpStatus(val code: Int) {
companion object {
val Ok = HttpStatus(200)
// etc
}
}```
is that from a http client or server? maybe open source?
πŸ‘€ 1
πŸ˜„ 1
s
Question driven OSS search 😬 If this is a client, or server I am also interested. Side-question: @christophsturm are you looking for a different http client/server?
c
I have my own small server OSS (that wraps undertow) and client (that wraps the java 11 http client) and maybe i should use that to improve my api design :)
πŸ‘€ 1
s
It was for a coroutine-first HTTP client as part of a work project, but it's not open source. I might have another go at it one day, though!
s
Curious, I've seen this a lot. So there is still a lot of small http clients around, alongside Ktor. I've had the same need, and I know many SDK developers also reinvent the wheel since nothing base or with a small footprint seems to be available. Ktor doesn't seem to fill this gap for many. It's a bit opinionated, and I don't always share the same opinion but I am always able to retrofit what I need in there. I should really write more about this... time. who has enough of it..
s
The reason that particular HTTP client was written was to act as a faΓ§ade so that we could decouple from Ktor and experiment with swapping it for something else. Ironic, since that's kind of what Ktor itself is supposed to be for. We were having a lot of odd networking/performance problems, and there was some evidence that they might be partly coming from Ktor itself.
s
We were having a lot of odd networking/performance problems, and there was some evidence that they might be partly coming from Ktor itself.
I've heard this several times before, both on client and server 😞
😒 1
s
I never got on well with the Ktor HTTP client. I find the pipeline/plugin design very confusing and hard to work with, especially with all the different pipeline stages. I also find the use of coroutine scopes and suspending functions doesn't match my expectations. The proliferation of extension functions makes it hard to mock and test. And there are some holes in the abstraction, especially when it comes to exceptions.
s
Right, I agree on all you said but It's been the best of all options for me, I like the design of Http4K but I miss coroutines and KMP support. I've partially build my own stack, but never published it out of fear of maintenance hell. I don't have enough spare time to cover that. Thanks for sharing your insights @Sam ☺️
s
Http4K with coroutines would be the dream!
πŸ‘† 1
s
Yes, I've considered forking to implement it which is what the maintainers suggest they're open to do. I know KMP is still on their roadmap, but they're waiting for KotlinX IO, and KotlinX Datetime to officially be stable. Perhaps we should open the discussion with them again, and we can implement coroutines support on JVM already. I think it's very doable without a noticeable difference in performance.
c
s
Nice, I'll have to take a look! Particularly interested in the streaming. I think the lack of an established coroutine IO ecosystem is a fundamental obstacle. Without one, I found there wasn't much so much point in a suspending HTTP client, because it would almost always end up needing to deliver data to a blocking API 😞
That's another thing I find confusing about Ktor, actually. It blurs the line between blocking and non-blocking APIs, so that it's often pretty hard to tell if a response is blocking, non-blocking or some buffered combination of the two 😬
βž• 1
Excellent use of 418 status code in the readme πŸ‘ πŸ«–
πŸ˜„ 1
c
i never got to use it for server side stuff in client projects but I used it a lot to mock http apis for testing, because it has such a compact api
but I used undertow a lot and its only a small wrapper. so i would trust it more than ktor