From 71f6a1eeee412045cc08ce8894194573362cb8f0 Mon Sep 17 00:00:00 2001 From: adamw Date: Thu, 31 Aug 2017 14:32:01 +0200 Subject: Response.body is now an Either[String, T], to handle cases when the status code isn't 2xx --- .../sttp/HttpURLConnectionHandler.scala | 12 ++++++++--- .../scala/com/softwaremill/sttp/Response.scala | 23 ++++++++++++++++++++-- .../main/scala/com/softwaremill/sttp/package.scala | 8 ++++++++ .../scala/com/softwaremill/sttp/RequestTests.scala | 2 +- 4 files changed, 39 insertions(+), 6 deletions(-) (limited to 'core') diff --git a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala index 548dd9b..ddc1293 100644 --- a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala +++ b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala @@ -191,9 +191,15 @@ object HttpURLConnectionHandler extends SttpHandler[Id, Nothing] { .filter(_._1 != null) .flatMap { case (k, vv) => vv.asScala.map((k, _)) } val contentEncoding = Option(c.getHeaderField(ContentEncodingHeader)) - Response(readResponseBody(wrapInput(contentEncoding, is), responseAs), - c.getResponseCode, - headers) + val code = c.getResponseCode + val wrappedIs = wrapInput(contentEncoding, is) + val body = if (codeIsSuccess(code)) { + Right(readResponseBody(wrappedIs, responseAs)) + } else { + Left(readResponseBody(wrappedIs, asString)) + } + + Response(body, code, headers) } private def readResponseBody[T](is: InputStream, diff --git a/core/src/main/scala/com/softwaremill/sttp/Response.scala b/core/src/main/scala/com/softwaremill/sttp/Response.scala index 44c39c3..5a3cfe3 100644 --- a/core/src/main/scala/com/softwaremill/sttp/Response.scala +++ b/core/src/main/scala/com/softwaremill/sttp/Response.scala @@ -15,9 +15,18 @@ import scala.collection.JavaConverters._ import scala.collection.immutable.Seq import scala.util.Try -case class Response[T](body: T, code: Int, headers: Seq[(String, String)]) { +/** + * @param body `Right(T)`, if the request was successful (status code 2xx). + * The body is then handled as specified in the request. + * `Left(String)`, if the request wasn't successful (status code + * 3xx, 4xx or 5xx). In this case, the response body is read into + * a `String`. + */ +case class Response[T](body: Either[String, T], + code: Int, + headers: Seq[(String, String)]) { def is200: Boolean = code == 200 - def isSuccess: Boolean = code >= 200 && code < 300 + def isSuccess: Boolean = codeIsSuccess(code) def isRedirect: Boolean = code >= 300 && code < 400 def isClientError: Boolean = code >= 400 && code < 500 def isServerError: Boolean = code >= 500 && code < 600 @@ -34,6 +43,16 @@ case class Response[T](body: T, code: Int, headers: Seq[(String, String)]) { def cookies: Seq[Cookie] = headers(SetCookieHeader) .flatMap(h => HttpCookie.parse(h).asScala.map(hc => Cookie.apply(hc, h))) + + /** + * Get the body of the response. If the status code wasn't 2xx (and there's + * no body to return), an exception is thrown, containing the status code + * and the response from the server. + */ + def unsafeBody: T = body match { + case Left(v) => throw new NoSuchElementException(s"Status code $code: $v") + case Right(v) => v + } } case class Cookie(name: String, diff --git a/core/src/main/scala/com/softwaremill/sttp/package.scala b/core/src/main/scala/com/softwaremill/sttp/package.scala index 3c4e844..24eb32c 100644 --- a/core/src/main/scala/com/softwaremill/sttp/package.scala +++ b/core/src/main/scala/com/softwaremill/sttp/package.scala @@ -251,6 +251,14 @@ package object sttp { transfer() } + private[sttp] def codeIsSuccess(c: Int): Boolean = c >= 200 && c < 300 + + private[sttp] def concatByteBuffers(bb1: ByteBuffer, bb2: ByteBuffer): ByteBuffer = + ByteBuffer + .allocate(bb1.array().length + bb2.array().length) + .put(bb1) + .put(bb2) + // uri interpolator implicit class UriContext(val sc: StringContext) extends AnyVal { diff --git a/core/src/test/scala/com/softwaremill/sttp/RequestTests.scala b/core/src/test/scala/com/softwaremill/sttp/RequestTests.scala index c6132c9..506167c 100644 --- a/core/src/test/scala/com/softwaremill/sttp/RequestTests.scala +++ b/core/src/test/scala/com/softwaremill/sttp/RequestTests.scala @@ -31,7 +31,7 @@ class RequestTests extends FlatSpec with Matchers { it should "set cookies from a response" in { val response = - Response((), + Response(Right(()), 0, List((SetCookieHeader, "k1=v1"), (SetCookieHeader, "k2=v2"))) sttp -- cgit v1.2.3