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