Created
January 4, 2019 02:31
-
-
Save afsalthaj/8a7a256884e1f269091e06fbc1dce44f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.effect.{ Effect, Sync } | |
import org.http4s.MediaType.`application/json` | |
import org.http4s.{ EntityDecoder, EntityEncoder, Headers, Method, Request, Status, Uri } | |
import org.http4s.client.Client | |
import org.http4s.headers.{ Accept, `Content-Type` } | |
import scalaz.{ EitherT, \/ } | |
import cats.syntax.applicative._ | |
import cats.syntax.functor._ | |
import org.http4s.client.blaze.Http1Client | |
import scalaz.syntax.either._ | |
final case class Http4sClient[F[_]: Sync] private (client: Client[F])(implicit M: cats.Monad[F]) { | |
implicit def scalazMonad: scalaz.Monad[F] = new scalaz.Monad[F] { | |
override def bind[A, B](fa: F[A])(f: A => F[B]): F[B] = M.flatMap(fa)(f) | |
override def point[A](a: => A): F[A] = M.pure(a) | |
} | |
def put[A, B](uri: String, body: A)(implicit E: EntityEncoder[F, A], D: EntityDecoder[F, B]): EitherT[F, String, B] = | |
for { | |
uri <- EitherT { parseUri(uri) } | |
req <- EitherT { | |
Request[F]( | |
method = Method.PUT, | |
uri = uri, | |
headers = Headers(Accept(`application/json`), `Content-Type`(`application/json`)) | |
).withBody[A](body).map(_.right[String]) | |
} | |
r <- EitherT { | |
fetch[B](req) | |
} | |
} yield r | |
def delete(uri: String): EitherT[F, String, Unit] = | |
for { | |
uri <- EitherT { parseUri(uri) } | |
req = Request[F](method = Method.DELETE, uri = uri) | |
r <- EitherT { fetch[Unit](req) } | |
} yield r | |
def get[B](uri: String)(implicit D: EntityDecoder[F, B]): EitherT[F, String, B] = | |
for { | |
uri <- EitherT { parseUri(uri) } | |
req = Request[F](method = Method.GET, uri = uri) | |
r <- EitherT { fetch[B](req) } | |
} yield r | |
private def parseUri(uri: String): F[String \/ Uri] = | |
\/.fromEither( | |
Uri.fromString(uri) | |
).leftMap(c => s"parse failure of uri. $c").pure[F] | |
private def fetch[B](req: Request[F])(implicit D: EntityDecoder[F, B]): F[String \/ B] = | |
client.fetch[Either[String, B]](req) { | |
case Status.Successful(r) => r.attemptAs[B].leftMap(_.message).value | |
case r => r.attemptAs[String].fold(t => Left(s"Failed to find the reason for failure in decoding. ${t.message}"), | |
t => Left(s"Request $req failed with status ${r.status.code} and body $t") | |
) | |
}.map(\/.fromEither) | |
} | |
object Http4sClient { | |
def mk[F[_]: Effect]: F[Http4sClient[F]] = | |
Http1Client[F]().map(Http4sClient(_)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment