David Kubecka
10/25/2024, 12:17 PMwithApiError which I call in my controller methods. Besides setting up Raise<ApiError> context, I'm also setting other common contexts. E.g. I inject an Account via withAccount function. This function can naturally raise an error (e.g. if the account does not exist), therefore it itself needs the Raise<ApiError> context. So my typical controller method looks like
withApiError {
withAccount {
// do some stuff which needs an account and can raise an error
}
}
So far so good.
The catch (I would say catch 22 🙂) is that in the withApiError function I would like to log some stuff which itself needs some account info. Obviouly, this can be used only if the account was successfully fetched. My question is how to best model this. Obviously I can do something like
withApiError { // this is just for the account
withAccount {
withApiErrorAndAccount { // inject full error context with access to account
// do some stuff which needs an account and can raise an error
}
}
}
Is there a more elegant way how to do that? Perhaps some clever tricks with nullability of receivers?Alejandro Serrano.Mena
10/25/2024, 12:21 PMval account = withApiError {
...
}
wihApiErrorAndAccount(account) {
...
}
but at the end of the day you have two different ApiError contexts that need to be injected separatelyDavid Kubecka
10/25/2024, 12:23 PMAlejandro Serrano.Mena
10/25/2024, 12:24 PMYoussef Shoaib [MOD]
10/25/2024, 12:42 PMwithAccount should inject a new Raise context that does the extra logging. Hence`withApiError` augments the pre-existing contextDavid Kubecka
11/08/2024, 9:55 AMclass TraceLogger(var accountName: String? = null) {
fun log() = traceClient.log(accountName)
}
fun <R, E : ApiError> withApiError(traceLogger: TraceLogger, block: Raise<E>.() -> R): R =
recover(block) { error ->
traceLogger.log()
...
}
fun <R, E : ApiError> withApiTraceError(
block: context(Account, Raise<E>) () -> R,
): R {
val traceLogger = TraceLogger() {
return withApiError(traceLogger) {
withAccount {
traceLogger.accountName = name
block(this@withAccount, this@withApiError)
}
}
}
I'm quite happy with this solution because it exactly mimics the actual data flow.