Hello, is there a way to be absolutely sure (excep...
# ktor
n
Hello, is there a way to be absolutely sure (except for some OOM error and such) to not crash when doing a Ktor GET or POST call ? I just want either the parsed result, either null. • I explored
runCatching
, which isn't great with coroutines, and I want to let errors through. • I explored catching
Exception
but that still wouldn't work with coroutines (catching
CancellationException
isn't a good idea) • I explored catching as many exceptions I could find in the Ktor source code, but what if I miss one ? This looks way to hacky, I must be missing something ?
s
If you want to catch
Exception
safely you can do this:
Copy code
try {
  doStuff()
} catch(e: Exception) {
  currentCoroutineContext().ensureActive() // makes cancellation work correctly
  handleError(e) 
}
Or, if you have #arrow, you could use its
NonFatal
function:
Copy code
try {
  doStuff()
} catch(t: Throwable) {
  if (NonFatal(t)) handleError(t) else throw t
}
I think you're right not to try and explicitly list all the different possible exceptions. Thanks to all the different engines and complex moving parts, the list would be endless.
n
Yes exactly, thanks, I will try with the
ensureActive
!
I end up with something like this, it still feels hacky, is there any room for improvement ?
Copy code
private suspend fun doStuff(payload: FooPayload) {
    val foo: String? = client.safeGet("foo") {
        contentType(ContentType.Application.Json)
    }
    
    println(foo)
    
    val bar: String? = client.safePost("bar") {
        contentType(ContentType.Application.Json)
        setBody(payload)
    }

    println(bar)
}

private suspend inline fun <reified T> HttpClient.safeGet(url: String, block: HttpRequestBuilder.() -> Unit): T? =
    safeRequest(url) {
        method = HttpMethod.Get
        block()
    }

private suspend inline fun <reified T> HttpClient.safePost(url: String, block: HttpRequestBuilder.() -> Unit): T? =
    safeRequest(url) {
        method = <http://HttpMethod.Post|HttpMethod.Post>
        block()
    }

private suspend inline fun <reified T> HttpClient.safeRequest(url: String, block: HttpRequestBuilder.() -> Unit): T? =
    try {
        request {
            url(url)
            block()
        }.body()
    } catch (e: Exception) {
        currentCoroutineContext().ensureActive()
        e.printStackTrace()
        null
    }