From ae08044da3202f26282f6f1bbf85fb1de1ec16a7 Mon Sep 17 00:00:00 2001 From: adamw Date: Wed, 11 Dec 2024 10:54:17 +0100 Subject: [PATCH] Keep .mapResponseRight in Request only --- .../src/main/scala/sttp/client4/request.scala | 28 ++++++++++--------- .../client4/testing/BackendStubTests.scala | 4 +-- .../scala/sttp/client4/testing/HttpTest.scala | 4 +-- .../sttp/client4/testing/SyncHttpTest.scala | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/core/src/main/scala/sttp/client4/request.scala b/core/src/main/scala/sttp/client4/request.scala index 7129cca21..df7730ca4 100644 --- a/core/src/main/scala/sttp/client4/request.scala +++ b/core/src/main/scala/sttp/client4/request.scala @@ -28,6 +28,8 @@ import sttp.attributes.AttributeMap trait GenericRequest[+T, -R] extends RequestBuilder[GenericRequest[T, R]] with RequestMetadata { def body: GenericRequestBody[R] def response: ResponseAsDelegate[T, R] + + /** Applies the given function `f` to the deserialized value `T`. */ def mapResponse[T2](f: T => T2): GenericRequest[T2, R] def toCurl: String = ToCurlConverter(this) @@ -124,6 +126,19 @@ case class Request[T]( def mapResponse[T2](f: T => T2): Request[T2] = response(response.map(f)) + /** If the type to which the response body should be deserialized is an `Either[A, B]`, applies the given function `f` + * to `Right` values. + * + * Because of type inference, the type of `f` must be fully provided, e.g. + * + * ``` + * asString.mapRight((s: String) => parse(s))` + * ``` + */ + def mapResponseRight[A, B, B2](f: B => B2)(implicit tIsEither: T <:< Either[A, B]): Request[Either[A, B2]] = response( + response.mapRight(f) + ) + /** Specifies that this is a WebSocket request. A [[WebSocketBackend]] will be required to send this request. */ def response[F[_], T2](ra: WebSocketResponseAs[F, T2]): WebSocketRequest[F, T2] = WebSocketRequest(method, uri, body, headers, ra, options, attributes) @@ -168,19 +183,6 @@ case class Request[T]( def send(backend: SyncBackend): Response[T] = backend.send(this) } -object Request { - implicit class RichRequestTEither[A, B](r: Request[Either[A, B]]) { - def mapResponseRight[B2](f: B => B2): Request[Either[A, B2]] = r.copy(response = r.response.mapRight(f)) - def responseGetRight: Request[B] = r.copy(response = r.response.orFail) - } - - implicit class RichRequestTEitherResponseException[HE, DE, B]( - r: Request[Either[ResponseException[HE, DE], B]] - ) { - def responseGetEither: Request[Either[HE, B]] = r.copy(response = r.response.orFailDeserialization) - } -} - // /** Describes an HTTP request, along with a description of how the response body should be handled. Either the request diff --git a/core/src/test/scala/sttp/client4/testing/BackendStubTests.scala b/core/src/test/scala/sttp/client4/testing/BackendStubTests.scala index 86b71f0be..7f91e7bad 100644 --- a/core/src/test/scala/sttp/client4/testing/BackendStubTests.scala +++ b/core/src/test/scala/sttp/client4/testing/BackendStubTests.scala @@ -144,8 +144,8 @@ class BackendStubTests extends AnyFlatSpec with Matchers with ScalaFutures { val result = basicRequest .get(uri"http://example.org") - .mapResponseRight(_.toInt) - .mapResponseRight(_ * 2) + .mapResponseRight((_: String).toInt) + .mapResponseRight((_: Int) * 2) .send(backend) result.body should be(Right(20)) diff --git a/core/src/test/scala/sttp/client4/testing/HttpTest.scala b/core/src/test/scala/sttp/client4/testing/HttpTest.scala index 41744a847..cb0b771c4 100644 --- a/core/src/test/scala/sttp/client4/testing/HttpTest.scala +++ b/core/src/test/scala/sttp/client4/testing/HttpTest.scala @@ -92,7 +92,7 @@ trait HttpTest[F[_]] "as string with mapping using mapResponse" in { postEcho .body(testBody) - .mapResponseRight(_.length) + .mapResponseRight((_: String).length) .send(backend) .toFuture() .map(response => response.body should be(Right(expectedPostEchoResponse.length))) @@ -572,7 +572,7 @@ trait HttpTest[F[_]] } "redirect when redirects should be followed, and the response is parsed" in { - r2.response(asString).mapResponseRight(_.toInt).send(backend).toFuture().map { resp => + r2.response(asString).mapResponseRight((_: String).toInt).send(backend).toFuture().map { resp => resp.code shouldBe StatusCode.Ok resp.body shouldBe Right(r4response.toInt) } diff --git a/core/src/test/scalanative/sttp/client4/testing/SyncHttpTest.scala b/core/src/test/scalanative/sttp/client4/testing/SyncHttpTest.scala index 2d9fb61d5..774234563 100644 --- a/core/src/test/scalanative/sttp/client4/testing/SyncHttpTest.scala +++ b/core/src/test/scalanative/sttp/client4/testing/SyncHttpTest.scala @@ -61,7 +61,7 @@ trait SyncHttpTest "as string with mapping using mapResponse" in { val response = postEcho .body(testBody) - .mapResponseRight(_.length) + .mapResponseRight((_: String).length) .send(backend) response.body should be(Right(expectedPostEchoResponse.length)) }