aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradamw <adam@warski.org>2017-11-16 12:22:50 +0100
committeradamw <adam@warski.org>2017-11-16 12:22:50 +0100
commit837c1a12d9bcf88e3d1055de7e1673a1b92bbe21 (patch)
tree520bb1e75f420048bc8d270e4fe395afd78f7206
parent585bfcc741109bef5c534ce245811595062af086 (diff)
downloadsttp-837c1a12d9bcf88e3d1055de7e1673a1b92bbe21.tar.gz
sttp-837c1a12d9bcf88e3d1055de7e1673a1b92bbe21.tar.bz2
sttp-837c1a12d9bcf88e3d1055de7e1673a1b92bbe21.zip
Add the possibility for monads to recover from errors
-rw-r--r--async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala4
-rw-r--r--async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala4
-rw-r--r--async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala4
-rw-r--r--async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala3
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/MonadError.scala16
-rw-r--r--okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala5
6 files changed, 36 insertions, 0 deletions
diff --git a/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala b/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala
index a38e08b..471d26c 100644
--- a/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala
+++ b/async-http-client-backend/cats/src/main/scala/com/softwaremill/sttp/asynchttpclient/cats/AsyncHttpClientCatsBackend.scala
@@ -78,4 +78,8 @@ private[cats] class AsyncMonad[F[_]](implicit F: Async[F])
F.flatMap(fa)(f)
override def error[T](t: Throwable): F[T] = F.raiseError(t)
+
+ override protected def handleWrappedError[T](rt: F[T])(
+ h: PartialFunction[Throwable, F[T]]): F[T] =
+ F.recoverWith(rt)(h)
}
diff --git a/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala b/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala
index 4dfc1da..8343a9b 100644
--- a/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala
+++ b/async-http-client-backend/fs2/src/main/scala/com/softwaremill/sttp/asynchttpclient/fs2/AsyncHttpClientFs2Backend.scala
@@ -108,4 +108,8 @@ private[fs2] class EffectMonad[F[_]](implicit F: Effect[F])
F.flatMap(fa)(f)
override def error[T](t: Throwable): F[T] = F.raiseError(t)
+
+ override protected def handleWrappedError[T](rt: F[T])(
+ h: PartialFunction[Throwable, F[T]]): F[T] =
+ F.recoverWith(rt)(h)
}
diff --git a/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala b/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala
index 9cb44f2..04df4ed 100644
--- a/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala
+++ b/async-http-client-backend/monix/src/main/scala/com/softwaremill/sttp/asynchttpclient/monix/AsyncHttpClientMonixBackend.scala
@@ -108,4 +108,8 @@ private[monix] object TaskMonad extends MonadAsyncError[Task] {
}
override def error[T](t: Throwable): Task[T] = Task.raiseError(t)
+
+ override protected def handleWrappedError[T](rt: Task[T])(
+ h: PartialFunction[Throwable, Task[T]]): Task[T] =
+ rt.onErrorRecoverWith(h)
}
diff --git a/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala b/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala
index 57e9577..3828233 100644
--- a/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala
+++ b/async-http-client-backend/scalaz/src/main/scala/com/softwaremill/sttp/asynchttpclient/scalaz/AsyncHttpClientScalazBackend.scala
@@ -74,4 +74,7 @@ private[scalaz] object TaskMonad extends MonadAsyncError[Task] {
}
override def error[T](t: Throwable): Task[T] = Task.fail(t)
+
+ override protected def handleWrappedError[T](rt: Task[T])(
+ h: PartialFunction[Throwable, Task[T]]): Task[T] = rt.handleWith(h)
}
diff --git a/core/src/main/scala/com/softwaremill/sttp/MonadError.scala b/core/src/main/scala/com/softwaremill/sttp/MonadError.scala
index 34edb0a..77c6235 100644
--- a/core/src/main/scala/com/softwaremill/sttp/MonadError.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/MonadError.scala
@@ -8,7 +8,17 @@ trait MonadError[R[_]] {
def unit[T](t: T): R[T]
def map[T, T2](fa: R[T])(f: T => T2): R[T2]
def flatMap[T, T2](fa: R[T])(f: T => R[T2]): R[T2]
+
def error[T](t: Throwable): R[T]
+ protected def handleWrappedError[T](rt: R[T])(
+ h: PartialFunction[Throwable, R[T]]): R[T]
+ def handleError[T](rt: => R[T])(h: PartialFunction[Throwable, R[T]]): R[T] = {
+ Try(rt) match {
+ case Success(v) => handleWrappedError(v)(h)
+ case Failure(e) if h.isDefinedAt(e) => h(e)
+ case Failure(e) => error(e)
+ }
+ }
def flatten[T](ffa: R[R[T]]): R[T] = flatMap[R[T], T](ffa)(identity)
@@ -26,7 +36,10 @@ object IdMonad extends MonadError[Id] {
override def unit[T](t: T): Id[T] = t
override def map[T, T2](fa: Id[T])(f: (T) => T2): Id[T2] = f(fa)
override def flatMap[T, T2](fa: Id[T])(f: (T) => Id[T2]): Id[T2] = f(fa)
+
override def error[T](t: Throwable): Id[T] = throw t
+ override protected def handleWrappedError[T](rt: Id[T])(
+ h: PartialFunction[Throwable, Id[T]]): Id[T] = rt
}
class FutureMonad(implicit ec: ExecutionContext)
@@ -36,7 +49,10 @@ class FutureMonad(implicit ec: ExecutionContext)
override def map[T, T2](fa: Future[T])(f: (T) => T2): Future[T2] = fa.map(f)
override def flatMap[T, T2](fa: Future[T])(f: (T) => Future[T2]): Future[T2] =
fa.flatMap(f)
+
override def error[T](t: Throwable): Future[T] = Future.failed(t)
+ override protected def handleWrappedError[T](rt: Future[T])(
+ h: PartialFunction[Throwable, Future[T]]): Future[T] = rt.recoverWith(h)
override def async[T](
register: ((Either[Throwable, T]) => Unit) => Unit): Future[T] = {
diff --git a/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala b/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala
index e85d271..f579ff5 100644
--- a/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala
+++ b/okhttp-backend/monix/src/main/scala/com/softwaremill/sttp/okhttp/monix/OkHttpMonixBackend.scala
@@ -117,4 +117,9 @@ private[monix] object TaskMonad extends MonadAsyncError[Task] {
}
override def error[T](t: Throwable): Task[T] = Task.raiseError(t)
+
+ override protected def handleWrappedError[T](rt: Task[T])(
+ h: PartialFunction[Throwable, Task[T]]): Task[T] = rt.onErrorRecoverWith {
+ case t => h(t)
+ }
}