From 76a9999731a795207c4350a3641454aeede93340 Mon Sep 17 00:00:00 2001 From: Mark de Jong Date: Mon, 27 Feb 2023 17:19:42 +0100 Subject: [PATCH 1/4] http4s: remove blaze dependency --- build.sbt | 4 ++-- .../sttp/client3/http4s/Http4sBackend.scala | 24 +------------------ .../http4s/Http4sHttpStreamingTest.scala | 4 ++-- .../sttp/client3/http4s/Http4sHttpTest.scala | 4 ++-- .../sttp/client3/http4s/Http4sBackend.scala | 23 ------------------ .../http4s/Http4sHttpStreamingTest.scala | 2 +- .../sttp/client3/http4s/Http4sHttpTest.scala | 2 +- 7 files changed, 9 insertions(+), 54 deletions(-) diff --git a/build.sbt b/build.sbt index 1d7152c73e..a7c030a00c 100644 --- a/build.sbt +++ b/build.sbt @@ -662,7 +662,7 @@ lazy val http4sCe2Backend = (projectMatrix in file("http4s-ce2-backend")) name := "http4s-ce2-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce2_version, - "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Optional + "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Test ) ) .jvmPlatform(scalaVersions = scala2alive) @@ -675,7 +675,7 @@ lazy val http4sBackend = (projectMatrix in file("http4s-backend")) name := "http4s-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce3_version, - "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Optional + "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Test ), evictionErrorLevel := Level.Info ) diff --git a/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala b/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala index 6bda7e8a77..215b06ab46 100644 --- a/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala +++ b/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala @@ -3,7 +3,7 @@ package sttp.client3.http4s import java.io.{InputStream, UnsupportedEncodingException} import java.nio.charset.Charset import cats.data.NonEmptyList -import cats.effect.{Async, Deferred, Resource} +import cats.effect.{Async, Deferred} import cats.implicits._ import cats.effect.implicits._ import fs2.io.file.Files @@ -11,7 +11,6 @@ import fs2.{Chunk, Stream} import org.http4s.{ContentCoding, EntityBody, Status, Request => Http4sRequest} import org.http4s import org.http4s.client.Client -import org.http4s.blaze.client.BlazeClientBuilder import org.typelevel.ci.CIString import sttp.capabilities.fs2.Fs2Streams import sttp.client3.http4s.Http4sBackend.EncodingHandler @@ -24,8 +23,6 @@ import sttp.client3.testing.SttpBackendStub import sttp.client3.ws.{GotAWebSocketException, NotAWebSocketException} import sttp.client3.{BasicRequestBody, NoBody, RequestBody, Response, SttpBackend, _} -import scala.concurrent.ExecutionContext - // needs http4s using cats-effect class Http4sBackend[F[_]: Async]( client: Client[F], @@ -293,25 +290,6 @@ object Http4sBackend { new Http4sBackend[F](client, customizeRequest, customEncodingHandler) ) - def usingBlazeClientBuilder[F[_]: Async]( - blazeClientBuilder: BlazeClientBuilder[F], - customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, - customEncodingHandler: EncodingHandler[F] = PartialFunction.empty - ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = { - blazeClientBuilder.resource.map(c => usingClient(c, customizeRequest, customEncodingHandler)) - } - - def usingDefaultBlazeClientBuilder[F[_]: Async]( - clientExecutionContext: ExecutionContext = ExecutionContext.global, - customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, - customEncodingHandler: EncodingHandler[F] = PartialFunction.empty - ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = - usingBlazeClientBuilder( - BlazeClientBuilder[F](clientExecutionContext), - customizeRequest, - customEncodingHandler - ) - /** Create a stub backend for testing, which uses the `F` response wrapper, and supports `Stream[F, Byte]` streaming. * * See [[sttp.client3.testing.SttpBackendStub]] for details on how to configure stub responses. diff --git a/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala b/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala index 252b394e60..2384ff8936 100644 --- a/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala +++ b/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala @@ -10,8 +10,8 @@ import sttp.capabilities.fs2.Fs2Streams class Http4sHttpStreamingTest extends Fs2StreamingTest { - private val blazeClientBuilder = BlazeClientBuilder[IO](ExecutionContext.global) + private val blazeClientBuilder = BlazeClientBuilder[IO] override val backend: SttpBackend[IO, Fs2Streams[IO]] = - Http4sBackend.usingBlazeClientBuilder(blazeClientBuilder).allocated.unsafeRunSync()._1 + blazeClientBuilder.resource.map(c => Http4sBackend.usingClient(c)).allocated.unsafeRunSync()._1 } diff --git a/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala b/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala index f86e3d8282..06e7f7bcdf 100644 --- a/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala +++ b/http4s-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala @@ -9,10 +9,10 @@ import sttp.client3.testing.HttpTest import scala.concurrent.ExecutionContext class Http4sHttpTest extends HttpTest[IO] with CatsRetryTest with CatsTestBase { - private val blazeClientBuilder = BlazeClientBuilder[IO](ExecutionContext.global) + private val blazeClientBuilder = BlazeClientBuilder[IO] override val backend: SttpBackend[IO, Any] = - Http4sBackend.usingBlazeClientBuilder(blazeClientBuilder).allocated.unsafeRunSync()._1 + blazeClientBuilder.resource.map(c => Http4sBackend.usingClient(c)).allocated.unsafeRunSync()._1 override protected def supportsRequestTimeout = false override protected def supportsCustomMultipartContentType = false diff --git a/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala b/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala index 6e31061686..a4f9007619 100644 --- a/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala +++ b/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala @@ -11,7 +11,6 @@ import fs2.{Chunk, Stream} import org.http4s.{ContentCoding, EntityBody, Status, Request => Http4sRequest} import org.http4s import org.http4s.client.Client -import org.http4s.blaze.client.BlazeClientBuilder import org.http4s.headers.`Content-Encoding` import org.typelevel.ci.CIString import sttp.capabilities.fs2.Fs2Streams @@ -293,28 +292,6 @@ object Http4sBackend { new Http4sBackend[F](client, blocker, customizeRequest, customEncodingHandler) ) - def usingBlazeClientBuilder[F[_]: ConcurrentEffect: ContextShift]( - blazeClientBuilder: BlazeClientBuilder[F], - blocker: Blocker, - customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, - customEncodingHandler: EncodingHandler[F] = PartialFunction.empty - ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = { - blazeClientBuilder.resource.map(c => usingClient(c, blocker, customizeRequest, customEncodingHandler)) - } - - def usingDefaultBlazeClientBuilder[F[_]: ConcurrentEffect: ContextShift]( - blocker: Blocker, - clientExecutionContext: ExecutionContext = ExecutionContext.global, - customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, - customEncodingHandler: EncodingHandler[F] = PartialFunction.empty - ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = - usingBlazeClientBuilder( - BlazeClientBuilder[F](clientExecutionContext), - blocker, - customizeRequest, - customEncodingHandler - ) - /** Create a stub backend for testing, which uses the `F` response wrapper, and supports `Stream[F, Byte]` streaming. * * See [[sttp.client3.testing.SttpBackendStub]] for details on how to configure stub responses. diff --git a/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala b/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala index c65157956e..7f422da3d6 100644 --- a/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala +++ b/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpStreamingTest.scala @@ -12,6 +12,6 @@ class Http4sHttpStreamingTest extends Fs2StreamingTest { private val blazeClientBuilder = BlazeClientBuilder[IO](ExecutionContext.global) override val backend: SttpBackend[IO, Fs2Streams[IO]] = - Http4sBackend.usingBlazeClientBuilder(blazeClientBuilder, blocker).allocated.unsafeRunSync()._1 + blazeClientBuilder.resource.map(c => Http4sBackend.usingClient(c, blocker)).allocated.unsafeRunSync()._1 } diff --git a/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala b/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala index 1026d6d909..66585346e7 100644 --- a/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala +++ b/http4s-ce2-backend/src/test/scala/sttp/client3/http4s/Http4sHttpTest.scala @@ -12,7 +12,7 @@ class Http4sHttpTest extends HttpTest[IO] with CatsTestBase { private val blazeClientBuilder = BlazeClientBuilder[IO](ExecutionContext.global) override val backend: SttpBackend[IO, Any] = - Http4sBackend.usingBlazeClientBuilder(blazeClientBuilder, blocker).allocated.unsafeRunSync()._1 + blazeClientBuilder.resource.map(c => Http4sBackend.usingClient(c, blocker)).allocated.unsafeRunSync()._1 override protected def supportsRequestTimeout = false override protected def supportsCustomMultipartContentType = false From 3b8eac3f5f7a6a5219cdc309c1b56f3de053aac5 Mon Sep 17 00:00:00 2001 From: Mark de Jong Date: Mon, 27 Feb 2023 17:37:51 +0100 Subject: [PATCH 2/4] format and update docs --- .../client3/armeria/zio/ArmeriaZioBackend.scala | 5 ++++- .../client3/armeria/zio/ArmeriaZioBackend.scala | 5 ++++- docs/backends/http4s.md | 13 +------------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/armeria-backend/zio/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala b/armeria-backend/zio/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala index 1a60fa95ed..615fe16199 100644 --- a/armeria-backend/zio/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala +++ b/armeria-backend/zio/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala @@ -1,6 +1,9 @@ package sttp.client3.armeria.zio -import _root_.zio.interop.reactivestreams.{publisherToStream => publisherToZioStream, streamToPublisher => zioStreamToPublisher} +import _root_.zio.interop.reactivestreams.{ + publisherToStream => publisherToZioStream, + streamToPublisher => zioStreamToPublisher +} import _root_.zio.{Chunk, Task, _} import com.linecorp.armeria.client.WebClient import com.linecorp.armeria.common.HttpData diff --git a/armeria-backend/zio1/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala b/armeria-backend/zio1/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala index 40d94b90e0..95ce0ff188 100644 --- a/armeria-backend/zio1/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala +++ b/armeria-backend/zio1/src/main/scala/sttp/client3/armeria/zio/ArmeriaZioBackend.scala @@ -12,7 +12,10 @@ import sttp.monad.MonadAsyncError import zio.{Chunk, Task} import zio.stream.Stream import _root_.zio._ -import _root_.zio.interop.reactivestreams.{publisherToStream => publisherToZioStream, streamToPublisher => zioStreamToPublisher} +import _root_.zio.interop.reactivestreams.{ + publisherToStream => publisherToZioStream, + streamToPublisher => zioStreamToPublisher +} import sttp.client3.armeria.ArmeriaWebClient.newClient private final class ArmeriaZioBackend(runtime: Runtime[Any], client: WebClient, closeFactory: Boolean) diff --git a/docs/backends/http4s.md b/docs/backends/http4s.md index b2b795d637..036a35a163 100644 --- a/docs/backends/http4s.md +++ b/docs/backends/http4s.md @@ -8,24 +8,13 @@ This backend is based on [http4s](https://http4s.org) (client) and is **asynchro "com.softwaremill.sttp.client3" %% "http4s-ce2-backend" % "@VERSION@" // for cats-effect 2.x & http4s 0.21.x ``` -The backend can be created in a couple of ways, e.g.: - -```scala mdoc:compile-only -import cats.effect._ -import sttp.capabilities.fs2.Fs2Streams -import sttp.client3._ -import sttp.client3.http4s._ - -Http4sBackend.usingDefaultBlazeClientBuilder[IO](): Resource[IO, SttpBackend[IO, Fs2Streams[IO]]] -``` - Sending a request is a non-blocking, lazily-evaluated operation and results in a wrapped response. There's a transitive dependency on `http4s`. There are also [other cats-effect-based backends](catseffect.md), which don't depend on http4s. Please note that: -* the backend contains an **optional** dependency on `http4s-blaze-client`, to provide the `Http4sBackend.usingBlazeClientBuilder` and `Http4sBackend.usingDefaultBlazeClientBuilder` methods. This makes the client usable with other http4s client implementations, without the need to depend on blaze. +* you have to build up your own `Client[F]` by either using _Blaze_, _Ember_ or something else * the backend does not support `SttpBackendOptions`, that is specifying proxy settings (proxies are not implemented in http4s, see [this issue](https://github.com/http4s/http4s/issues/251)), as well as configuring the connect timeout * the backend does not support the `RequestT.options.readTimeout` option From 4f3a12fc84f1ac0114f98ff913f74b28aaf072c3 Mon Sep 17 00:00:00 2001 From: Mark de Jong Date: Wed, 1 Mar 2023 16:30:04 +0100 Subject: [PATCH 3/4] format and update docs --- build.sbt | 5 +++-- .../sttp/client3/http4s/Http4sBackend.scala | 22 ++++++++++++++++++- .../sttp/client3/http4s/Http4sBackend.scala | 10 +++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index a7c030a00c..4ff3095fbc 100644 --- a/build.sbt +++ b/build.sbt @@ -662,7 +662,7 @@ lazy val http4sCe2Backend = (projectMatrix in file("http4s-ce2-backend")) name := "http4s-ce2-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce2_version, - "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Test + "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Provided ) ) .jvmPlatform(scalaVersions = scala2alive) @@ -675,7 +675,8 @@ lazy val http4sBackend = (projectMatrix in file("http4s-backend")) name := "http4s-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce3_version, - "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Test + "org.http4s" %% "http4s-ember-client" % "0.23.13" % Provided, + "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Provided, ), evictionErrorLevel := Level.Info ) diff --git a/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala b/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala index 215b06ab46..cf67077a5b 100644 --- a/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala +++ b/http4s-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala @@ -3,14 +3,16 @@ package sttp.client3.http4s import java.io.{InputStream, UnsupportedEncodingException} import java.nio.charset.Charset import cats.data.NonEmptyList -import cats.effect.{Async, Deferred} +import cats.effect.{Async, Deferred, Resource} import cats.implicits._ import cats.effect.implicits._ import fs2.io.file.Files import fs2.{Chunk, Stream} import org.http4s.{ContentCoding, EntityBody, Status, Request => Http4sRequest} import org.http4s +import org.http4s.blaze.client.BlazeClientBuilder import org.http4s.client.Client +import org.http4s.ember.client.EmberClientBuilder import org.typelevel.ci.CIString import sttp.capabilities.fs2.Fs2Streams import sttp.client3.http4s.Http4sBackend.EncodingHandler @@ -23,6 +25,8 @@ import sttp.client3.testing.SttpBackendStub import sttp.client3.ws.{GotAWebSocketException, NotAWebSocketException} import sttp.client3.{BasicRequestBody, NoBody, RequestBody, Response, SttpBackend, _} +import scala.concurrent.ExecutionContext + // needs http4s using cats-effect class Http4sBackend[F[_]: Async]( client: Client[F], @@ -290,6 +294,22 @@ object Http4sBackend { new Http4sBackend[F](client, customizeRequest, customEncodingHandler) ) + def usingBlazeClientBuilder[F[_]: Async]( + blazeClientBuilder: BlazeClientBuilder[F], + customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, + customEncodingHandler: EncodingHandler[F] = PartialFunction.empty + ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = { + blazeClientBuilder.resource.map(c => usingClient(c, customizeRequest, customEncodingHandler)) + } + + def usingEmberClientBuilder[F[_]: Async]( + emberClientBuilder: EmberClientBuilder[F], + customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, + customEncodingHandler: EncodingHandler[F] = PartialFunction.empty + ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = { + emberClientBuilder.build.map(c => usingClient(c, customizeRequest, customEncodingHandler)) + } + /** Create a stub backend for testing, which uses the `F` response wrapper, and supports `Stream[F, Byte]` streaming. * * See [[sttp.client3.testing.SttpBackendStub]] for details on how to configure stub responses. diff --git a/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala b/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala index a4f9007619..f9e5e13235 100644 --- a/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala +++ b/http4s-ce2-backend/src/main/scala/sttp/client3/http4s/Http4sBackend.scala @@ -10,6 +10,7 @@ import cats.effect.implicits._ import fs2.{Chunk, Stream} import org.http4s.{ContentCoding, EntityBody, Status, Request => Http4sRequest} import org.http4s +import org.http4s.blaze.client.BlazeClientBuilder import org.http4s.client.Client import org.http4s.headers.`Content-Encoding` import org.typelevel.ci.CIString @@ -292,6 +293,15 @@ object Http4sBackend { new Http4sBackend[F](client, blocker, customizeRequest, customEncodingHandler) ) + def usingBlazeClientBuilder[F[_]: ConcurrentEffect: ContextShift]( + blazeClientBuilder: BlazeClientBuilder[F], + blocker: Blocker, + customizeRequest: Http4sRequest[F] => Http4sRequest[F] = identity[Http4sRequest[F]] _, + customEncodingHandler: EncodingHandler[F] = PartialFunction.empty + ): Resource[F, SttpBackend[F, Fs2Streams[F]]] = { + blazeClientBuilder.resource.map(c => usingClient(c, blocker, customizeRequest, customEncodingHandler)) + } + /** Create a stub backend for testing, which uses the `F` response wrapper, and supports `Stream[F, Byte]` streaming. * * See [[sttp.client3.testing.SttpBackendStub]] for details on how to configure stub responses. From 5caf6f66a10e261dfa1d71f38737b41848e054b3 Mon Sep 17 00:00:00 2001 From: Mark de Jong Date: Wed, 1 Mar 2023 16:30:46 +0100 Subject: [PATCH 4/4] Set to optional instead of provided --- build.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 4ff3095fbc..2ac2cb2374 100644 --- a/build.sbt +++ b/build.sbt @@ -662,7 +662,7 @@ lazy val http4sCe2Backend = (projectMatrix in file("http4s-ce2-backend")) name := "http4s-ce2-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce2_version, - "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Provided + "org.http4s" %% "http4s-blaze-client" % http4s_ce2_version % Optional ) ) .jvmPlatform(scalaVersions = scala2alive) @@ -675,8 +675,8 @@ lazy val http4sBackend = (projectMatrix in file("http4s-backend")) name := "http4s-backend", libraryDependencies ++= Seq( "org.http4s" %% "http4s-client" % http4s_ce3_version, - "org.http4s" %% "http4s-ember-client" % "0.23.13" % Provided, - "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Provided, + "org.http4s" %% "http4s-ember-client" % "0.23.13" % Optional, + "org.http4s" %% "http4s-blaze-client" % "0.23.13" % Optional, ), evictionErrorLevel := Level.Info )