aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md21
-rw-r--r--async-http-client-handler/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/FutureAsyncHttpClientHandler.scala33
-rw-r--r--async-http-client-handler/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/ScalazAsyncHttpClientHandler.scala32
-rw-r--r--async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/internal/AsyncHttpClientHandler.scala (renamed from async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientHandler.scala)47
-rw-r--r--build.sbt23
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala9
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala5
7 files changed, 135 insertions, 35 deletions
diff --git a/README.md b/README.md
index 357142e..b5b62e9 100644
--- a/README.md
+++ b/README.md
@@ -240,24 +240,33 @@ val response: Future[Response[Source[ByteString, Any]]] =
To use, add the following dependency to your project:
```scala
-"com.softwaremill.sttp" %% "async-http-client-handler" % version
+"com.softwaremill.sttp" %% "async-http-client-handler-future" % version
+// or
+"com.softwaremill.sttp" %% "async-http-client-handler-scalaz" % version
```
This handler depends on [async-http-handler](https://github.com/AsyncHttpClient/async-http-client).
A fully **asynchronous** handler, which uses [Netty](http://netty.io) behind the
-scenes. Sending a request returns a response wrapped in a `Future`. Different
-wrappers will be added in the future.
+scenes.
+
+The responses are either wrapped in a `Future`, or a
+[Scalaz](https://github.com/scalaz/scalaz) `Task`, depending on the
+dependency chosen. In the latter case, there's an additional transitive
+dependency on `scalaz-concurrent`.
Next you'll need to add an implicit value:
```scala
-implicit val sttpHandler = new AsyncHttpClientHandler()
+implicit val sttpHandler = new FutureAsyncHttpClientHandler()
+
+// or, if you're using the scalaz version:
+implicit val sttpHandler = new ScalazAsyncHttpClientHandler()
// or, if you'd like to use custom configuration:
-implicit val sttpHandler = new AsyncHttpClientHandler(asyncHttpClientConfig)
+implicit val sttpHandler = new FutureAsyncHttpClientHandler(asyncHttpClientConfig)
// or, if you'd like to instantiate the AsyncHttpClient yourself:
-implicit val sttpHandler = new AsyncHttpClientHandler(asyncHttpClient)
+implicit val sttpHandler = new FutureAsyncHttpClientHandler(asyncHttpClient)
```
Streaming is not (yet) supported.
diff --git a/async-http-client-handler/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/FutureAsyncHttpClientHandler.scala b/async-http-client-handler/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/FutureAsyncHttpClientHandler.scala
new file mode 100644
index 0000000..624c51b
--- /dev/null
+++ b/async-http-client-handler/future/src/main/scala/com/softwaremill/sttp/asynchttpclient/future/FutureAsyncHttpClientHandler.scala
@@ -0,0 +1,33 @@
+package com.softwaremill.sttp.asynchttpclient.future
+
+import com.softwaremill.sttp.asynchttpclient.internal.{
+ AsyncHttpClientHandler,
+ WrapperFromAsync
+}
+import org.asynchttpclient.{
+ AsyncHttpClient,
+ AsyncHttpClientConfig,
+ DefaultAsyncHttpClient
+}
+
+import scala.concurrent.{Future, Promise}
+
+class FutureAsyncHttpClientHandler(asyncHttpClient: AsyncHttpClient)
+ extends AsyncHttpClientHandler[Future](asyncHttpClient, FutureFromAsync) {
+
+ def this() = this(new DefaultAsyncHttpClient())
+ def this(cfg: AsyncHttpClientConfig) = this(new DefaultAsyncHttpClient(cfg))
+}
+
+private[asynchttpclient] object FutureFromAsync
+ extends WrapperFromAsync[Future] {
+ override def apply[T](
+ register: ((Either[Throwable, T]) => Unit) => Unit): Future[T] = {
+ val p = Promise[T]()
+ register {
+ case Left(t) => p.failure(t)
+ case Right(t) => p.success(t)
+ }
+ p.future
+ }
+}
diff --git a/async-http-client-handler/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/ScalazAsyncHttpClientHandler.scala b/async-http-client-handler/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/ScalazAsyncHttpClientHandler.scala
new file mode 100644
index 0000000..e2c664c
--- /dev/null
+++ b/async-http-client-handler/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/ScalazAsyncHttpClientHandler.scala
@@ -0,0 +1,32 @@
+package com.softwaremill.sttp.asynchttpclient.scalaz
+
+import com.softwaremill.sttp.asynchttpclient.internal.{
+ AsyncHttpClientHandler,
+ WrapperFromAsync
+}
+import org.asynchttpclient.{
+ AsyncHttpClient,
+ AsyncHttpClientConfig,
+ DefaultAsyncHttpClient
+}
+
+import scalaz.{-\/, \/-}
+import scalaz.concurrent.Task
+
+class ScalazAsyncHttpClientHandler(asyncHttpClient: AsyncHttpClient)
+ extends AsyncHttpClientHandler[Task](asyncHttpClient, TaskFromAsync) {
+
+ def this() = this(new DefaultAsyncHttpClient())
+ def this(cfg: AsyncHttpClientConfig) = this(new DefaultAsyncHttpClient(cfg))
+}
+
+private[asynchttpclient] object TaskFromAsync extends WrapperFromAsync[Task] {
+ override def apply[T](
+ register: ((Either[Throwable, T]) => Unit) => Unit): Task[T] =
+ Task.async { cb =>
+ register {
+ case Left(t) => cb(-\/(t))
+ case Right(t) => cb(\/-(t))
+ }
+ }
+}
diff --git a/async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientHandler.scala b/async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/internal/AsyncHttpClientHandler.scala
index ecd49cd..924e0bc 100644
--- a/async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/AsyncHttpClientHandler.scala
+++ b/async-http-client-handler/src/main/scala/com/softwaremill/sttp/asynchttpclient/internal/AsyncHttpClientHandler.scala
@@ -1,4 +1,4 @@
-package com.softwaremill.sttp.asynchttpclient
+package com.softwaremill.sttp.asynchttpclient.internal
import java.nio.charset.Charset
@@ -7,34 +7,31 @@ import com.softwaremill.sttp.{Request, Response, SttpHandler}
import org.asynchttpclient.{
AsyncCompletionHandler,
AsyncHttpClient,
- AsyncHttpClientConfig,
- DefaultAsyncHttpClient,
RequestBuilder,
Request => AsyncRequest,
Response => AsyncResponse
}
-import scala.concurrent.{Future, Promise}
import scala.collection.JavaConverters._
-
-class AsyncHttpClientHandler(asyncHttpClient: AsyncHttpClient)
- extends SttpHandler[Future, Nothing] {
- def this() = this(new DefaultAsyncHttpClient())
- def this(cfg: AsyncHttpClientConfig) = this(new DefaultAsyncHttpClient(cfg))
-
- override def send[T](r: Request[T, Nothing]): Future[Response[T]] = {
- val p = Promise[Response[T]]()
- asyncHttpClient
- .prepareRequest(requestToAsync(r))
- .execute(new AsyncCompletionHandler[AsyncResponse] {
- override def onCompleted(response: AsyncResponse): AsyncResponse = {
- p.success(readResponse(response, r.responseAs))
- response
- }
- override def onThrowable(t: Throwable): Unit = p.failure(t)
- })
-
- p.future
+import scala.language.higherKinds
+
+private[asynchttpclient] class AsyncHttpClientHandler[R[_]](
+ asyncHttpClient: AsyncHttpClient,
+ wrapper: WrapperFromAsync[R])
+ extends SttpHandler[R, Nothing] {
+
+ override def send[T](r: Request[T, Nothing]): R[Response[T]] = {
+ wrapper { cb =>
+ asyncHttpClient
+ .prepareRequest(requestToAsync(r))
+ .execute(new AsyncCompletionHandler[AsyncResponse] {
+ override def onCompleted(response: AsyncResponse): AsyncResponse = {
+ cb(Right(readResponse(response, r.responseAs)))
+ response
+ }
+ override def onThrowable(t: Throwable): Unit = cb(Left(t))
+ })
+ }
}
private def requestToAsync(r: Request[_, Nothing]): AsyncRequest = {
@@ -111,3 +108,7 @@ class AsyncHttpClientHandler(asyncHttpClient: AsyncHttpClient)
}
}
}
+
+private[asynchttpclient] trait WrapperFromAsync[R[_]] {
+ def apply[T](register: (Either[Throwable, T] => Unit) => Unit): R[T]
+}
diff --git a/build.sbt b/build.sbt
index 6817ad3..063e7fe 100644
--- a/build.sbt
+++ b/build.sbt
@@ -66,7 +66,7 @@ lazy val akkaHttpHandler: Project = (project in file("akka-http-handler"))
libraryDependencies ++= Seq(
akkaHttp
)
- ) dependsOn (core)
+ ) dependsOn core
lazy val asyncHttpClientHandler: Project = (project in file(
"async-http-client-handler"))
@@ -76,7 +76,24 @@ lazy val asyncHttpClientHandler: Project = (project in file(
libraryDependencies ++= Seq(
"org.asynchttpclient" % "async-http-client" % "2.0.33"
)
- ) dependsOn (core)
+ ) dependsOn core
+
+lazy val futureAsyncHttpClientHandler: Project = (project in file(
+ "async-http-client-handler/future"))
+ .settings(commonSettings: _*)
+ .settings(
+ name := "async-http-client-handler-future"
+ ) dependsOn asyncHttpClientHandler
+
+lazy val scalazAsyncHttpClientHandler: Project = (project in file(
+ "async-http-client-handler/scalaz"))
+ .settings(commonSettings: _*)
+ .settings(
+ name := "async-http-client-handler-scalaz",
+ libraryDependencies ++= Seq(
+ "org.scalaz" %% "scalaz-concurrent" % "7.2.14"
+ )
+ ) dependsOn asyncHttpClientHandler
lazy val tests: Project = (project in file("tests"))
.settings(commonSettings: _*)
@@ -91,4 +108,4 @@ lazy val tests: Project = (project in file("tests"))
"ch.qos.logback" % "logback-classic" % "1.2.3"
).map(_ % "test"),
libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test"
- ) dependsOn (core, akkaHttpHandler, asyncHttpClientHandler)
+ ) dependsOn (core, akkaHttpHandler, futureAsyncHttpClientHandler, scalazAsyncHttpClientHandler)
diff --git a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
index 96fbbae..f456fb1 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/BasicTests.scala
@@ -16,7 +16,8 @@ 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.AsyncHttpClientHandler
+import com.softwaremill.sttp.asynchttpclient.future.FutureAsyncHttpClientHandler
+import com.softwaremill.sttp.asynchttpclient.scalaz.ScalazAsyncHttpClientHandler
import scala.language.higherKinds
@@ -117,8 +118,10 @@ class BasicTests
ForceWrappedValue.id)
runTests("Akka HTTP")(new AkkaHttpSttpHandler(actorSystem),
ForceWrappedValue.future)
- runTests("Async Http Client")(new AsyncHttpClientHandler(),
- ForceWrappedValue.future)
+ runTests("Async Http Client - Future")(new FutureAsyncHttpClientHandler(),
+ ForceWrappedValue.future)
+ runTests("Async Http Client - Scalaz")(new ScalazAsyncHttpClientHandler(),
+ ForceWrappedValue.scalazTask)
def runTests[R[_]](name: String)(
implicit handler: SttpHandler[R, Nothing],
diff --git a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
index 6d83848..9114d8b 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/testHelpers.scala
@@ -9,6 +9,7 @@ import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.Future
import scala.language.higherKinds
+import scalaz.concurrent.Task
trait TestHttpServer extends BeforeAndAfterAll with ScalaFutures {
this: Suite =>
@@ -43,6 +44,10 @@ trait ForceWrapped extends ScalaFutures { this: Suite =>
override def force[T](wrapped: Future[T]): T =
wrapped.futureValue
}
+ val scalazTask = new ForceWrappedValue[Task] {
+ override def force[T](wrapped: Task[T]): T =
+ wrapped.unsafePerformSync
+ }
}
implicit class ForceDecorator[R[_], T](wrapped: R[T]) {
def force()(implicit fwv: ForceWrappedValue[R]): T = fwv.force(wrapped)