Hello! I have a REST API that needs to calls: one...
# arrow
k
Hello! I have a REST API that needs to calls: one to
/playlists
to get the list of playlist, and then for each playlist I have to call
/playlist/<id>
to get more information about the playlists themselves. All API calls are suspending. And I always return
Either<Error, T>
. Can I somehow leverage Arrow to do n requests in parallel? A higher-level abstraction over
parZip
basically. I want to query
/playlist/<id>
with 5 simultaneous requests and do it for all playlists returned from
/playlists
.
d
I was trying to find an idea for this (if I understand your question), over here: https://kotlinlang.slack.com/archives/C5UPMM0A0/p1699955211044099
s
Hey @kotlinforandroid, If I understood your problem correctly, then this should work. The alternative for
parZip
but for
Iterable<A>
is
parMap
, analogue to
map
from Kotlin Std.
Copy code
data class Playlist(val id: Long, val ids: List<Long>)
object GetPlaylistResult

suspend fun getPlaylists(): List<Playlist> = TODO()

suspend fun getPlaylist(id: Long): GetPlaylistResult = TODO()

fun main(): Unit = runBlocking {
  getPlaylists().parMap(concurrency = 5) { playlist ->
    getPlaylist(playlist.id)
  } // List<GetPlaylistResult>
}
arrow intensifies 2
d
In the question, he says all the requests return an
Either
, would parMap short-circuit on error of either getPlaylists or one of the getPlaylist calls?
k
Yes, my API is like this:
Copy code
interface API {
    fun getPlaylists(): Either<NotAuthenticated, List<Playlist>>
    fun getPlaylistDetails(playlistId: PlaylistId): Either<NoPlaylistFound, PlaylistDetails>
}
I think maybe
parMapOrAccumulate
might be the function I am looking for.
s
Oh, I'm sorry.
Copy code
fun main(): Unit = runBlocking {
  either {
    getPlaylists().parMap(concurrency = 5) { playlist ->
      getPlaylist(playlist.id).bind()
        // GetPlaylistResult
    } // List<GetPlaylistResult>
  } // Either<E, List<GetPlaylistResult>>
}
The difference between
parMapOrAccumulate
is that
parMap
will stop with the first
Either.Left
it encounters. Whilst
parMapOrAccumulate
guarantees to finishes all request (unless
Throwable
is encountered), and returns all
Either.Left
as a
NonEmptyList<A> : Iterable<A>
.
d
Not:
Copy code
fun main(): Unit = runBlocking {
  either { ///      v
    getPlaylists().bind().parMap(concurrency = 5) { playlist ->
      getPlaylist(playlist.id).bind()
        // GetPlaylistResult
    } // List<GetPlaylistResult>
  } // Either<E, List<GetPlaylistResult>>
}
?
s
Yes, you're right @dave08!
Sorry, just writing pseudo code in chat is not great 😅 We need an integrated IntelliJ in Slack to write & typecheck snippets 🤣
😂 3
K 2