I am trying to write a small library for GitHub's API. And I am trying to simulate the behavior of Github4s's library, here is an example of this library:
val user1 = Github(accessToken).users.get("rafaparadela")
object ProgramEval {
val u1 = user1.exec[Eval, HttpResponse[String]]().value
}
import cats.implicits._
import github4s.GithubResponses.GHResult
ProgramEval.u1 match {
// Here the actual value of the request is returned,
// not the same as Future's onComplete, where the return type is Unit
case Right(GHResult(result, status, headers)) => result.login
case Left(e) => e.getMessage
}
I am quoting the docs:
Every Github4s API call returns a GHIO[GHResponse[A]] which is an alias for Free[Github4s, GHResponse[A]].
GHResponse[A] is, in turn, a type alias for Either[GHException, GHResult[A]].
GHResult contains the result A given by Github as well as the status code and headers of the response:
At some point, they are making an HttpRequest
using HttpClient.scala
How could I replicate this behavior myself? I have tried using Cats.Eval as in the example, but I end up having the same Future[String]
.
Also, I an facing with some nesting problems as I make request, for example, to get a list of contributors of an organization I need to make two HttpRequest
:
This result on a Future[List[Future[Users]]]
, and I face the same problem as above, in order to obtain the results, I have to do:
(result:Future[List[Future[Users]]]) onComplete { users =>
users.foreach {
_ onComplete {
// Process result
}
}
}
But I would like to return the value, as github4s
. I've been reading about Cats's Applicative and Traversable Functors without luck.
You can convert List[Future]
to Future[List]
using Future.sequence
and then squash nested futures.
The resulting code:
val input: Future[List[Future[Users]]] = ???
implicit val ec: ExecutionContext = ExecutionContext.global
val result: Future[List[Users]] = input.flatMap(list => Future.sequence(list))