curious what folks' preferred means of handling no...
# ktor
c
curious what folks' preferred means of handling non-2XX responses are when using ktor client? • using
expectSuccess = true
and a global exception handler for ClientRequestExceptions? • using
expectSuccess = true
and using the client inside a try/catch block • using
expectSuccess = false
and checking the
response.status
and adding control flow for success/failure statuses accordingly? • something else?? I'm also curious what people's opinions are for choosing an interface for downstream functions that use the results of network requests. I've seen a variety of thoughts including - • Using sealed interfaces with Success & Failure objects that wrap the response • Using nulls to represent non-2xx responses • Wrapping client request functions with "safe" extension functions that catches & handle exceptions... then returning either nulls or Success/Failure objects • Have the control flow represent the happy path only, with any exceptions being thrown by the ktor client istelf, and eventually handled at a top level exception handler
r
personally I've been preferring bullet #3, and using a sealed interface to return two serializable response types (assuming the success and errors have distinct schemas) that way I build a "ThingClient" class that uses a KtorClient internally, but still reveals something fairly 1:1 with the service api, and encourages the consumer of the client to unpack and handle all possibilities successfully
👍 1
above that level, I tend to prefer sealed interfaces with all the possible scenarios my system is interested in handling distinctly - sometimes you may want more fine-toothed understanding of error sources, sometimes a simple "Unknown" or "Failure" type is plenty. Depends on the domain.
s
Hi @Rob Murdock, do you any sample repo up where you have done this and can share it? I have just started with Ktor myself and want to see how such scenarios are being handled.
s
I'd probably make one place where such responses are mapped to an arrow-kt Either, and Right is the data type I expect, and Left is a sealed hierarchy of the possible errors, where if I need to know what exactly went wrong I can look into that.
👏 1
👍 1
s
Thanks @Rob Murdock! I'll check it out 👍
c
Thanks for the input! For now I'm keen on a style that uses - • One common sealed class used for all api results (using generics / type parameters / variance) • a wrapper function for try/catching common api exceptions • I'm using KMP so this wrapper is an expected interface with actual android & ios implementations that catch the exceptions specific to their respective http clients I like this style because it keeps the functions in the client file clean & simple - they don't have try/catch blocks and their method signature is typed. Additionally, exception mapping is centralised in the wrapper. I added a sample of what this looks like here - https://github.com/cmederos/snippets/blob/main/ResourceExample.kts
🚀 1
j
sealed classes combined with a Ktor plugin so you get:
Copy code
suspend fun main() {
    val either: NetworkEither<ErrorDTO, DogDTO> = client.get("dog/$code").body()
    either.fold(...)
}

@Serializable data class DogDTO(val id: Int, val name: String, val age: Int)

@Serializable data class ErrorDTO(val message: String)
K 2
👀 1
m
Hi @Javier sorry for the ping, do you have a small code snippet that you can share, I think I'm following the wrong path & I can't make it right: https://kotlinlang.slack.com/archives/C0A974TJ9/p1694989445812659
j
I have a library which is not documented yet. I will try to add some samples and move it to KMP so I can share it here.
105 Views