https://kotlinlang.org logo
#getting-started
Title
# getting-started
q

queen-of-idleness

07/28/2020, 9:33 AM
Hi Folks, I post this in getting-started because I just switched from Scala (http4s, cats) to Kotlin. Please feel free to point me to another channel if there is a better fitting one. As a context you might consider my perspective is quite Scala driven.
Given
Two external services should be called successively. Calling service B depends on the response of service A. The responses are wrapped in this monad result type. There are two places where an error response can happen. In that case the flow should be aborted immediately and the error should be converted to a http response with a human readable body. We want to stay with the standard library, http4k, result4k and coroutines. So we don't want to use a library like arrow or similar.
Issues
1. Is there a better mechanism to chain the flow? 2. Should calling external services be wrapped in some structure like 
Future
 or 
Deferred
 ? We might have to wait for their result but can't do anything in parallel in the meantime. This is the simplified, compiling pseudo code:
Copy code
data class HttpResponse(val status: Int, val body: String)

typealias RequestA = String
typealias ResponseA = String
typealias ErrorA = String

typealias RequestB = String
typealias ResponseB = String
typealias ErrorB = String

fun someFunction(
        callServiceA: (RequestA) -> Result<ResponseA, ErrorA>,
        callServiceB: (RequestB) -> Result<ResponseB, ErrorB>,
        input: String
): HttpResponse =
        callServiceA(input)
                .mapFailure { HttpResponse(409, "please provide a valid id") }
                .flatMap { responseA ->
                    callServiceB(responseA)
                            .mapFailure { HttpResponse(401, "you don't exist") }
                            .map { responseB -> HttpResponse(200, responseB.capitalize()) }
                }.get()
👍 2
p

Paul Martin

07/30/2020, 5:02 PM
in our projects we return an
Error
sealed class in our `Result`s which has a
toErrorResponse()
method which converts the error to an http response. something like this:
Copy code
sealed class Error(open val message: String) {
    fun toErrorResponse(): HttpResponse = when (this) {
        is ValidationFailure -> HttpResponse(409, this.message)
        is Unauthorised -> HttpResponse(401, this.message)
    }
}
data class ValidationFailure(override val message: String): Error (message)
data class Unauthorised(override val message: String): Error (message)

data class HttpResponse(val status: Int, val body: String)

typealias RequestA = String
typealias ResponseA = String
typealias RequestB = String
typealias ResponseB = String

fun someFunction(
    callServiceA: (RequestA) -> Result<ResponseA, Error>,
    callServiceB: (RequestB) -> Result<ResponseB, Error>,
    input: String
): HttpResponse =
    callServiceA(input)
        .flatMap { responseA -> callServiceB(responseA) }
        .map { responseB -> HttpResponse(200, responseB.capitalize()) }
        .mapFailure { it.toErrorResponse() }
        .get()
so your
callServiceA
might fail with an Error of
ValidationFailure("please provide a valid id")
and
callServiceB
might fail with an Error of
Unauthorised("you don't exist")
, which then get converted to the appropriate http response in the
mapFailure
q

queen-of-idleness

09/09/2020, 6:39 AM
@Paul Martin thank you very much for your response. (And sorry for my late reaction - I have been away from my machine for a month.)
👍 1
4 Views