Good morning! I want to confirm what’s the “best p...
# arrow
a
Good morning! I want to confirm what’s the “best practice” or correct way in the following case(s):
Copy code
// say I have something like this in my ktor endpoint

post<Resource>{
  applicationService.doSomething.fold(
    ifLeft= {call.respond(HttpStatusCode.BadRequest, it)},
    ifRight = {call.respond(HttpStatusCode.OK, // it)}
  )
}
I was wondering if this is the correct usage because fold is used to transform either into a value of C. Would it be better to change the order to
call.respond(result.fold( ifLeft, ifRight))
? What about when we deal with side effects? (say we want to log and then respond when its a left) I suppose we use
onLeft
in those cases? (since it takes an action that is (left: A) -> Unit))
Copy code
result.onLeft { 
  logger.log
  call.respond(400)
}
call.respond(200)
I’ve also seen some people do
result.mapLeft{call.respond(400,it)}
and then respond 200 after but I feel like that’s not meant to be used that way.. So, is there a “best practice” in these cases? Any of them work but I want to use them how they’re meant to be used. Sorry for my lack of knowledge in FP, have a nice day!
s
Good morning @Alejandro Ramos, Right, or wrong, is a bit arbitrary here since most operations use
fold
underneath. You can also just use
when
instead of
fold
.
Copy code
when(val result = applicationService.doSomething) {
  is Right -> call.respond(OK, result.value)
  is Left -> call.respond(BadRequest, result.value)
}
That would be the most vanilla Kotlin, and then there are several way to achieve the same thing:
Copy code
fold(ifLeft, ifRight)
map(ifRight).getOrElse(ifLeft)
either { ifRight(bind()) }.getOrElse(ifLeft)
What I think is nice, and I've used this in a few place but it depends a bit on how your errors are modelled.
Copy code
inline suspend fun <refied A : Any> Either<MyError, A>.respond(
  call: ApplicationCall,
  statusCode: HttpStatusCode
): Unit =
  when(val result = applicationService.doSomething) {
    is Right -> call.respond(OK, result.value)
    is Left -> when(value) {
      is UserNotFound -> call.respond(BadRequest, result.value)
      is Unauthorized -> call.respond(Unauthorized, result.value)
      // and so on
    }
  }
Then in my application code I do:
Copy code
applicationService.doSomething.respond(call, OK)
💜 1
K 1
With
context receivers
you can remove the
call
parameters.
context(PipelineContext<ApplicationCall, Unit>)
a
Thank you for the fast response, as always! @simon.vergauwen I see, so there is no one way of doing it, and it depends on preference basically. I was just worrying about using the functions as their signature implies (like onLeft -> Unit for side effects and such). I’ll talk to my team and see which way they prefer of handling them!
What I think is nice, and I’ve used this in a few place
Wow! This is a pretty way of abstracting this, I like it. I think I’ll try implementing it that way to further simplify our controller layerarrow intensifies
🙌 1
arrow intensifies 2