diff options
Diffstat (limited to 'core/src/main/scala/com/softwaremill')
-rw-r--r-- | core/src/main/scala/com/softwaremill/sttp/MonadError.scala | 3 | ||||
-rw-r--r-- | core/src/main/scala/com/softwaremill/sttp/model/ResponseAs.scala | 46 |
2 files changed, 43 insertions, 6 deletions
diff --git a/core/src/main/scala/com/softwaremill/sttp/MonadError.scala b/core/src/main/scala/com/softwaremill/sttp/MonadError.scala index e5e7ab8..40cea4b 100644 --- a/core/src/main/scala/com/softwaremill/sttp/MonadError.scala +++ b/core/src/main/scala/com/softwaremill/sttp/MonadError.scala @@ -2,6 +2,7 @@ package com.softwaremill.sttp import scala.concurrent.{ExecutionContext, Future, Promise} import scala.language.higherKinds +import scala.util.Try trait MonadError[R[_]] { def unit[T](t: T): R[T] @@ -10,6 +11,8 @@ trait MonadError[R[_]] { def error[T](t: Throwable): R[T] def flatten[T](ffa: R[R[T]]): R[T] = flatMap[R[T], T](ffa, identity) + + def fromTry[T](t: Try[T]): R[T] = t.fold(error, unit) } trait MonadAsyncError[R[_]] extends MonadError[R] { diff --git a/core/src/main/scala/com/softwaremill/sttp/model/ResponseAs.scala b/core/src/main/scala/com/softwaremill/sttp/model/ResponseAs.scala index cf9bc12..3862483 100644 --- a/core/src/main/scala/com/softwaremill/sttp/model/ResponseAs.scala +++ b/core/src/main/scala/com/softwaremill/sttp/model/ResponseAs.scala @@ -2,24 +2,37 @@ package com.softwaremill.sttp.model import java.net.URLDecoder +import com.softwaremill.sttp.MonadError + import scala.collection.immutable.Seq +import scala.language.higherKinds +import scala.util.Try /** * @tparam T Target type as which the response will be read. * @tparam S If `T` is a stream, the type of the stream. Otherwise, `Nothing`. */ sealed trait ResponseAs[T, +S] { - def map[T2](f: T => T2): ResponseAs[T2, S] = + def map[T2](f: T => T2): ResponseAs[T2, S] +} + +/** + * Response handling specification which isn't derived from another response + * handling method, but needs to be handled directly by the backend. + */ +sealed trait BasicResponseAs[T, +S] extends ResponseAs[T, S] { + override def map[T2](f: (T) => T2): ResponseAs[T2, S] = MappedResponseAs[T, T2, S](this, f) } -case object IgnoreResponse extends ResponseAs[Unit, Nothing] +case object IgnoreResponse extends BasicResponseAs[Unit, Nothing] case class ResponseAsString(encoding: String) - extends ResponseAs[String, Nothing] -case object ResponseAsByteArray extends ResponseAs[Array[Byte], Nothing] + extends BasicResponseAs[String, Nothing] +case object ResponseAsByteArray extends BasicResponseAs[Array[Byte], Nothing] case class ResponseAsStream[T, S]()(implicit val responseIsStream: S =:= T) - extends ResponseAs[T, S] -case class MappedResponseAs[T, T2, S](raw: ResponseAs[T, S], g: T => T2) + extends BasicResponseAs[T, S] + +case class MappedResponseAs[T, T2, S](raw: BasicResponseAs[T, S], g: T => T2) extends ResponseAs[T2, S] { override def map[T3](f: T2 => T3): ResponseAs[T3, S] = MappedResponseAs[T, T3, S](raw, g andThen f) @@ -38,4 +51,25 @@ object ResponseAs { case _ => None }) } + + /** + * Handles responses according to the given specification when basic + * response specifications can be handled eagerly, that is without + * wrapping the result in the target monad (`handleBasic` returns + * `Try[T]`, not `R[T]`). + */ + private[sttp] trait EagerResponseHandler[S] { + def handleBasic[T](bra: BasicResponseAs[T, S]): Try[T] + + def handle[T, R[_]](responseAs: ResponseAs[T, S], + responseMonad: MonadError[R]): R[T] = { + + responseAs match { + case mra @ MappedResponseAs(raw, g) => + responseMonad.map(responseMonad.fromTry(handleBasic(mra.raw)), mra.g) + case bra: BasicResponseAs[T, S] => + responseMonad.fromTry(handleBasic(bra)) + } + } + } } |