aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Madsen <bm@aeons.dk>2017-08-04 10:21:30 +0200
committerBjørn Madsen <bm@aeons.dk>2017-08-04 10:28:10 +0200
commit24f6fac2f4ca3a82eb776a8756a16785716489f8 (patch)
tree7ae32664d823913be38d5d8eb4c5d9eef1111559
parentc81487ff2c6d0a4a886ac9ceb7a7a89a39eb5c88 (diff)
downloadsttp-24f6fac2f4ca3a82eb776a8756a16785716489f8.tar.gz
sttp-24f6fac2f4ca3a82eb776a8756a16785716489f8.tar.bz2
sttp-24f6fac2f4ca3a82eb776a8756a16785716489f8.zip
Add support for cats effect with AHC backend
-rw-r--r--async-http-client-handler/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/CatsAsyncHttpClientHandler.scala61
-rw-r--r--build.sbt12
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala4
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala4
4 files changed, 80 insertions, 1 deletions
diff --git a/async-http-client-handler/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/CatsAsyncHttpClientHandler.scala b/async-http-client-handler/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/CatsAsyncHttpClientHandler.scala
new file mode 100644
index 0000000..cfd9c5b
--- /dev/null
+++ b/async-http-client-handler/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/CatsAsyncHttpClientHandler.scala
@@ -0,0 +1,61 @@
+package com.softwaremill.sttp.asynchttpclient.cats
+
+import java.nio.ByteBuffer
+
+import cats.effect._
+import com.softwaremill.sttp.asynchttpclient.AsyncHttpClientHandler
+import com.softwaremill.sttp.{MonadAsyncError, SttpHandler}
+import org.asynchttpclient.{
+ AsyncHttpClient,
+ AsyncHttpClientConfig,
+ DefaultAsyncHttpClient
+}
+import org.reactivestreams.Publisher
+
+import scala.language.higherKinds
+
+class CatsAsyncHttpClientHandler[F[_]: Async](asyncHttpClient: AsyncHttpClient,
+ closeClient: Boolean)
+ extends AsyncHttpClientHandler[F, Nothing](asyncHttpClient,
+ new AsyncMonad,
+ closeClient) {
+ override protected def streamBodyToPublisher(
+ s: Nothing): Publisher[ByteBuffer] = s // nothing is everything
+
+ override protected def publisherToStreamBody(
+ p: Publisher[ByteBuffer]): Nothing =
+ throw new IllegalStateException("This handler does not support streaming")
+}
+
+object CatsAsyncHttpClientHandler {
+
+ def apply[F[_]: Async](): SttpHandler[F, Nothing] =
+ new CatsAsyncHttpClientHandler(new DefaultAsyncHttpClient(),
+ closeClient = true)
+
+ def usingConfig[F[_]: Async](
+ cfg: AsyncHttpClientConfig): SttpHandler[F, Nothing] =
+ new CatsAsyncHttpClientHandler(new DefaultAsyncHttpClient(cfg),
+ closeClient = true)
+
+ def usingClient[F[_]: Async](
+ client: AsyncHttpClient): SttpHandler[F, Nothing] =
+ new CatsAsyncHttpClientHandler(client, closeClient = false)
+}
+
+private[cats] class AsyncMonad[F[_]](implicit F: Async[F])
+ extends MonadAsyncError[F] {
+
+ override def async[T](
+ register: ((Either[Throwable, T]) => Unit) => Unit): F[T] =
+ F.async(register)
+
+ override def unit[T](t: T): F[T] = F.pure(t)
+
+ override def map[T, T2](fa: F[T], f: (T) => T2): F[T2] = F.map(fa)(f)
+
+ override def flatMap[T, T2](fa: F[T], f: (T) => F[T2]): F[T2] =
+ F.flatMap(fa)(f)
+
+ override def error[T](t: Throwable): F[T] = F.raiseError(t)
+}
diff --git a/build.sbt b/build.sbt
index 10e1dd5..b8dfed6 100644
--- a/build.sbt
+++ b/build.sbt
@@ -105,6 +105,16 @@ lazy val monixAsyncHttpClientHandler: Project = (project in file(
)
) dependsOn asyncHttpClientHandler
+lazy val catsAsyncHttpClientHandler: Project = (project in file(
+ "async-http-client-handler/cats"))
+ .settings(commonSettings: _*)
+ .settings(
+ name := "async-http-client-handler-cats",
+ libraryDependencies ++= Seq(
+ "org.typelevel" %% "cats-effect" % "0.4"
+ )
+ ) dependsOn asyncHttpClientHandler
+
lazy val okhttpClientHandler: Project = (project in file(
"okhttp-client-handler"))
.settings(commonSettings: _*)
@@ -129,4 +139,4 @@ lazy val tests: Project = (project in file("tests"))
).map(_ % "test"),
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test"
) dependsOn (core, akkaHttpHandler, futureAsyncHttpClientHandler, scalazAsyncHttpClientHandler,
-monixAsyncHttpClientHandler, okhttpClientHandler)
+monixAsyncHttpClientHandler, catsAsyncHttpClientHandler, okhttpClientHandler)
diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
index 5f17a7a..36c82ef 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
@@ -16,6 +16,7 @@ import com.typesafe.scalalogging.StrictLogging
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers}
import better.files._
+import com.softwaremill.sttp.asynchttpclient.cats.CatsAsyncHttpClientHandler
import com.softwaremill.sttp.asynchttpclient.future.FutureAsyncHttpClientHandler
import com.softwaremill.sttp.asynchttpclient.monix.MonixAsyncHttpClientHandler
import com.softwaremill.sttp.asynchttpclient.scalaz.ScalazAsyncHttpClientHandler
@@ -130,6 +131,9 @@ class BasicTests
ForceWrappedValue.scalazTask)
runTests("Async Http Client - Monix")(MonixAsyncHttpClientHandler(),
ForceWrappedValue.monixTask)
+ runTests("Async Http Client - Cats Effect")(
+ CatsAsyncHttpClientHandler[cats.effect.IO](),
+ ForceWrappedValue.catsIo)
runTests("OkHttpSyncClientHandler")(OkHttpSyncClientHandler(),
ForceWrappedValue.id)
runTests("OkHttpSyncClientHandler - Future")(OkHttpFutureClientHandler(),
diff --git a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
index 9bf68bb..558e9dd 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
@@ -53,6 +53,10 @@ trait ForceWrapped extends ScalaFutures { this: Suite =>
override def force[T](wrapped: monix.eval.Task[T]): T =
wrapped.runAsync.futureValue
}
+ val catsIo = new ForceWrappedValue[cats.effect.IO] {
+ override def force[T](wrapped: cats.effect.IO[T]): T =
+ wrapped.unsafeRunSync
+ }
}
implicit class ForceDecorator[R[_], T](wrapped: R[T]) {
def force()(implicit fwv: ForceWrappedValue[R]): T = fwv.force(wrapped)