You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hello
In my application I'm using AkkaHttpBackend which is SttpBackend[Future,...]. In the logic of the application I'm using cats.effect.IO. The sttp3 provides new syntax for my use case, which is mapK, so I was happy to use that while I was migrating from sttp2 to sttp3. After mapping I have SttpBackend[IO, Any], so my expectation was: if I invoke .send then I have got IO[Response[...]] and since IO is referential transparent I can use the benefits of that in my application.
The bellow example shows that it is not true:
importcats.effect._importcats.~>importorg.scalatest.matchers.should.Matchersimportorg.scalatest.wordspec.AsyncWordSpecimportsttp.capabilities.Effectimportsttp.client3._importsttp.client3.asynchttpclient.future.AsyncHttpClientFutureBackendimportsttp.client3.impl.cats.implicits._importsttp.model.Uriimportscala.concurrent._classDeferringFutureBackendSpecextendsAsyncWordSpecwithMatchers {
implicitvalcontextShift:ContextShift[IO] =IO.contextShift(ExecutionContext.global)
defcreateBackend():SttpBackend[IO, Any] = {
valfutureToIO= λ[Future~>IO](future =>Async.fromFuture(IO(future)))
valioToFuture= λ[IO~>Future](_.unsafeToFuture())
valmockBackend:SttpBackend[Future, Any] =AsyncHttpClientFutureBackend.stub().whenAnyRequest.thenRespondCyclic("1", "2")
valioBackend:SttpBackend[IO, Any] = mockBackend.mapK(futureToIO, ioToFuture)
ioBackend
// new DeferringSttpBackend(ioBackend) // this will work
}
classDeferringSttpBackend(delegate: SttpBackend[IO, Any]) extendsDelegateSttpBackend(delegate) {
overridedefsend[T, R>:Effect[IO]](request: Request[T, R]):IO[Response[T]] =Sync[IO].defer(delegate.send(request))
overridedefclose():IO[Unit] =Sync[IO].defer(delegate.close())
}
"defer action for each request" in {
valbackend:SttpBackend[IO, Any] = createBackend()
valsendAction:IO[Response[String]] = backend.send(basicRequest.response(asStringAlways).get(Uri("localhost")))
for {
a <- sendAction
b <- sendAction
} yield {
a.body shouldBe "1"
b.body shouldBe "2"// TestFailedException: expected "2" actual "1"
}
}.unsafeToFuture()
}
after wrapping ioBackend using DeferringSttpBackend the test is passing.
after thinking about it for a while I understand why it is happening, because futureToIO is impure.
my questions are:
If you would see this code for the first time what behavior would you expect. If I'm using SttpBackend[IO,...] I'm expecting it to be referential transparent.
Is this a bug or bad configuration?
Is this worth mentioning in the documentation? Maybe add a new example called "converting SttpBackend[Future, P] to SttpBackend[IO, P]"
Is there a place for DeferringSttpBackend in the public api so everyone can use it?
The text was updated successfully, but these errors were encountered:
Nice catch :) I think the problem here is that you can't use FunctionK to transform a Future into an IO, as it doesn't use by-name parameters. And that's equally true for sttp client and any other usage.
At least documenting how to convert a future-based backend into any cast-effect-supported effect is certainly a good idea. I'd probably just implement the backend, though, as a backend wrapper, without using .mapK (but copying & improving its implementation - the MappedKSttpBackend).
Hello
In my application I'm using AkkaHttpBackend which is
SttpBackend[Future,...]
. In the logic of the application I'm usingcats.effect.IO
. The sttp3 provides new syntax for my use case, which ismapK
, so I was happy to use that while I was migrating from sttp2 to sttp3. After mapping I haveSttpBackend[IO, Any]
, so my expectation was: if I invoke.send
then I have gotIO[Response[...]]
and since IO is referential transparent I can use the benefits of that in my application.The bellow example shows that it is not true:
after wrapping
ioBackend
usingDeferringSttpBackend
the test is passing.after thinking about it for a while I understand why it is happening, because
futureToIO
is impure.my questions are:
SttpBackend[IO,...]
I'm expecting it to be referential transparent.SttpBackend[Future, P]
toSttpBackend[IO, P]
"DeferringSttpBackend
in the public api so everyone can use it?The text was updated successfully, but these errors were encountered: