Fred Friis
03/24/2021, 12:56 AMclass UserResource (private val userDao: UserDao) {
@POST
fun post(CreateUserRequest createUserRequest){
return IO
.fx {
userDao.create()
}
}.runUnsafe something something
.toEither()
.fold({ left ->
Response.serverError()
},{ right ->
Response.success(right)
})
}simon.vergauwen
03/24/2021, 7:48 AMsuspend, which has the same capabilities as IO.
Where suspend has support in the compiler, and thus has much nicer performance and syntax in the Kotlin language. Therefore suspend was chosen over IO, and IO is being deprecated.
That being said, when you're doing something like useDoa.createUser(request) there is typically scheduling involved to go to an different Thread, or rather pool, for doing blocking tasks like network request or database queries. Therefore you want to use suspend which has such capabilities.
This would change your signature to:
suspend fun create(request: InternalCreateUserRequest): Either<IError, User>.
Now that the function is suspend, and has the capabilities of going async you can access a bunch of concurrency operators in KotlinX Coroutines or Arrow Fx Coroutines and can rewrite your code to.
override fun create(request: InternalCreateUserRequest): Either<IError, User> =
Either.catch {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
userDao.createUser(request) //returns User but can throw
}
}.mapLeft { throwable ->
InternalServerError("Failed to create user", throwable)
}
Which with IO is the equivalent of IO<Either<IError, User>>, and this already shows that suspend is much more superior in Kotlin than IO.
This would change your usage site to:
@POST
fun post(CreateUserRequest createUserRequest): Response = runBlocking {
create(createUserRequest.toInternal())
.fold({ left ->
Response.serverError()
},{ right ->
Response.success(right)
})
}
Here runBlocking from KotlinX Coroutines is the equivalent of unsafeRunXXX from IO. It takes a lazy suspend function and runs it and rethrows any uncaught errors.
The idea in FP is that if in your application you use suspend that it should bubble all the way to the edge of your application. In this case your @Post function because that's the outer edge of your code. Ideally you'd use a framework that supports suspend so you don't even ever call runBlocking. Ktor has such capabilities, and Spring WebFlux also.
Doing so protects you from calling suspend functions from non-suspend functions. Or in other words it protects you from calling side-effecting functions from pure functions.simon.vergauwen
03/24/2021, 7:48 AMiguissouma
03/24/2021, 4:04 PMFred Friis
03/24/2021, 11:31 PM