diff --git a/README.md b/README.md index d5715c0f29..b431c14355 100755 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ ## Welcome! [sttp client](https://github.com/softwaremill/sttp) is an open-source library which provides a clean, programmer-friendly API to describe HTTP -requests and how to handle responses. Requests are sent using one of the backends, which wrap other Scala or Java HTTP client implementations. The backends can integrate with a variety of Scala stacks, providing both synchronous and asynchronous, procedural and functional interfaces. +requests and how to handle responses. Requests are sent using one of the backends, which wrap lower-level Scala or Java HTTP client implementations. The backends can integrate with a variety of Scala stacks, providing both synchronous and asynchronous, procedural and functional interfaces. -Backend implementations include ones based on [akka-http](https://doc.akka.io/docs/akka-http/current/scala/http/), [http4s](https://http4s.org), [OkHttp](http://square.github.io/okhttp/), and HTTP clients which ship with Java. They integrate with [Akka](https://akka.io), [Monix](https://monix.io), [fs2](https://github.com/functional-streams-for-scala/fs2), [cats-effect](https://github.com/typelevel/cats-effect), [scalaz](https://github.com/scalaz/scalaz) and [ZIO](https://github.com/zio/zio). Supported Scala versions include 2.11, 2.12, 2.13 and 3, Scala.JS and Scala Native. +Backend implementations include the HTTP client that is shipped with Java, as well as ones based on [akka-http](https://doc.akka.io/docs/akka-http/current/scala/http/), [http4s](https://http4s.org), [OkHttp](http://square.github.io/okhttp/). They integrate with [Akka](https://akka.io), [Monix](https://monix.io), [fs2](https://github.com/functional-streams-for-scala/fs2), [cats-effect](https://github.com/typelevel/cats-effect), [scalaz](https://github.com/scalaz/scalaz) and [ZIO](https://github.com/zio/zio). Supported Scala versions include 2.12, 2.13 and 3, Scala.JS and Scala Native; supported Java versions include 11+. Here's a quick example of sttp client in action: @@ -29,7 +29,7 @@ val query = "http language:scala" // `sort` is removed, as the value is not defined val request = basicRequest.get(uri"https://api.github.com/search/repositories?q=$query&sort=$sort") -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val response = request.send(backend) // response.header(...): Option[String] @@ -51,18 +51,29 @@ sttp (v1) documentation is available at [sttp.softwaremill.com/en/v1](https://st scaladoc is available at [https://www.javadoc.io](https://www.javadoc.io/doc/com.softwaremill.sttp.client4/core_2.12/3.8.13) +## Quickstart with scala-cli + +Add the following directive to the top of your scala file to add the core sttp dependency: +If you are using [scala-cli](https://scala-cli.virtuslab.org), you can quickly start experimenting with sttp by copy-pasting the following: + +``` +//> using lib "com.softwaremill.sttp.client4:core:3.8.13" +import sttp.client4.quick._ +quickRequest.get(uri"http://httpbin.org/ip").send() +``` + +The `quick` package import brings in the sttp API and a pre-configured, global synchronous backend instance. + ## Quickstart with Ammonite -If you are an [Ammonite](http://ammonite.io) user, you can quickly start experimenting with sttp by copy-pasting the following: +Similarly, using [Ammonite](http://ammonite.io): ```scala import $ivy.`com.softwaremill.sttp.client4::core:3.8.13` import sttp.client4.quick._ -quickRequest.get(uri"http://httpbin.org/ip").send(backend) +quickRequest.get(uri"http://httpbin.org/ip").send() ``` -This brings in the sttp API and a synchronous backend instance. - ## Quickstart with sbt Add the following dependency: @@ -102,7 +113,7 @@ If you'd like to run the tests using *only* the JVM backend, execute: `sbt rootJ ### Importing into IntelliJ -By default, when importing to IntelliJ, only the Scala 2.13/JVM subprojects will be imported. This is controlled by the `ideSkipProject` setting in `build.sbt` (inside `commonSettings`). +By default, when importing to IntelliJ or Metals, only the Scala 2.13/JVM subprojects will be imported. This is controlled by the `ideSkipProject` setting in `build.sbt` (inside `commonSettings`). If you'd like to work on a different platform or Scala version, simply change this setting temporarily so that the correct subprojects are imported. For example: @@ -150,4 +161,4 @@ We offer commercial support for sttp and related technologies, as well as develo ## Copyright -Copyright (C) 2017-2022 SoftwareMill [https://softwaremill.com](https://softwaremill.com). +Copyright (C) 2017-2023 SoftwareMill [https://softwaremill.com](https://softwaremill.com). diff --git a/core/src/main/scalajs/sttp/client4/DefaultFutureBackend.scala b/core/src/main/scalajs/sttp/client4/DefaultFutureBackend.scala new file mode 100644 index 0000000000..a1022bc123 --- /dev/null +++ b/core/src/main/scalajs/sttp/client4/DefaultFutureBackend.scala @@ -0,0 +1,21 @@ +package sttp.client4 + +import sttp.client4.fetch.FetchBackend +import sttp.client4.testing.WebSocketBackendStub + +import scala.concurrent.{ExecutionContext, Future} + +object DefaultFutureBackend { + + /** Creates a default websocket-capable backend which uses [[Future]] to represent side effects, with the given + * `options`. Currently based on [[FetchBackend]]. + */ + def apply()(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackend[Future] = FetchBackend() + + /** Create a stub backend for testing, which uses [[Future]] to represent side effects, and doesn't support streaming. + * + * See [[WebSocketBackendStub]] for details on how to configure stub responses. + */ + def stub(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackendStub[Future] = + WebSocketBackendStub.asynchronousFuture +} diff --git a/core/src/main/scalajs/sttp/client4/quick.scala b/core/src/main/scalajs/sttp/client4/quick.scala index 8f5c5fb674..fece12580c 100644 --- a/core/src/main/scalajs/sttp/client4/quick.scala +++ b/core/src/main/scalajs/sttp/client4/quick.scala @@ -1,11 +1,9 @@ package sttp.client4 -import sttp.client4.fetch.FetchBackend - import scala.concurrent.Future object quick extends SttpApi { - lazy val backend: Backend[Future] = FetchBackend() + lazy val backend: Backend[Future] = DefaultFutureBackend() implicit class RichRequest[T](val request: Request[T]) { def send(): Future[Response[T]] = backend.send(request) diff --git a/core/src/main/scalajvm/sttp/client4/DefaultFutureBackend.scala b/core/src/main/scalajvm/sttp/client4/DefaultFutureBackend.scala new file mode 100644 index 0000000000..954cbf7a61 --- /dev/null +++ b/core/src/main/scalajvm/sttp/client4/DefaultFutureBackend.scala @@ -0,0 +1,25 @@ +package sttp.client4 + +import sttp.client4.httpclient.HttpClientFutureBackend +import sttp.client4.testing.WebSocketBackendStub + +import scala.concurrent.{ExecutionContext, Future} + +object DefaultFutureBackend { + + /** Creates a default websocket-capable backend which uses [[Future]] to represent side effects, with the given + * `options`. Currently based on [[HttpClientFutureBackend]]. + */ + def apply( + options: BackendOptions = BackendOptions.Default + )(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackend[Future] = { + HttpClientFutureBackend(options, identity, PartialFunction.empty) + } + + /** Create a stub backend for testing, which uses [[Future]] to represent side effects, and doesn't support streaming. + * + * See [[WebSocketBackendStub]] for details on how to configure stub responses. + */ + def stub(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackendStub[Future] = + WebSocketBackendStub.asynchronousFuture +} diff --git a/core/src/main/scalajvm/sttp/client4/DefaultSyncBackend.scala b/core/src/main/scalajvm/sttp/client4/DefaultSyncBackend.scala new file mode 100644 index 0000000000..36107eaf35 --- /dev/null +++ b/core/src/main/scalajvm/sttp/client4/DefaultSyncBackend.scala @@ -0,0 +1,16 @@ +package sttp.client4 + +import sttp.client4.httpclient.HttpClientSyncBackend +import sttp.client4.testing.SyncBackendStub + +object DefaultSyncBackend { + + /** Creates a default synchronous backend with the given `options`, which is currently based on + * [[HttpClientSyncBackend]]. + */ + def apply(options: BackendOptions = BackendOptions.Default): SyncBackend = + HttpClientSyncBackend(options, identity, PartialFunction.empty) + + /** Create a stub backend for testing. See [[SyncBackendStub]] for details on how to configure stub responses. */ + def stub: SyncBackendStub = SyncBackendStub +} diff --git a/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientBackend.scala b/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientBackend.scala index 77554c23c3..db39ac5397 100644 --- a/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientBackend.scala +++ b/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientBackend.scala @@ -133,10 +133,6 @@ object HttpClientBackend { } } - // Left here for bincompat - private[client4] def defaultClient(options: BackendOptions): HttpClient = - defaultClient(options, None) - private[client4] def defaultClient(options: BackendOptions, executor: Option[Executor]): HttpClient = { var clientBuilder = HttpClient .newBuilder() diff --git a/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientFutureBackend.scala b/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientFutureBackend.scala index c7530aa121..3e37ddde45 100644 --- a/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientFutureBackend.scala +++ b/core/src/main/scalajvm/sttp/client4/httpclient/HttpClientFutureBackend.scala @@ -79,12 +79,14 @@ object HttpClientFutureBackend { customizeRequest: HttpRequest => HttpRequest, customEncodingHandler: InputStreamEncodingHandler )(implicit ec: ExecutionContext): WebSocketBackend[Future] = - wrappers.FollowRedirectsBackend(new HttpClientFutureBackend(client, closeClient, customizeRequest, customEncodingHandler)) + wrappers.FollowRedirectsBackend( + new HttpClientFutureBackend(client, closeClient, customizeRequest, customEncodingHandler) + ) def apply( - options: BackendOptions = BackendOptions.Default, - customizeRequest: HttpRequest => HttpRequest = identity, - customEncodingHandler: InputStreamEncodingHandler = PartialFunction.empty + options: BackendOptions = BackendOptions.Default, + customizeRequest: HttpRequest => HttpRequest = identity, + customEncodingHandler: InputStreamEncodingHandler = PartialFunction.empty )(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackend[Future] = { val executor = Some(ec).collect { case executor: Executor => executor } HttpClientFutureBackend( @@ -107,9 +109,9 @@ object HttpClientFutureBackend { customEncodingHandler ) - /** Create a stub backend for testing, which uses the [[Future]] response wrapper, and doesn't support streaming. + /** Create a stub backend for testing, which uses [[Future]] to represent side effects, and doesn't support streaming. * - * See [[SttpBackendStub]] for details on how to configure stub responses. + * See [[WebSocketBackendStub]] for details on how to configure stub responses. */ def stub(implicit ec: ExecutionContext = ExecutionContext.global): WebSocketBackendStub[Future] = WebSocketBackendStub.asynchronousFuture diff --git a/core/src/main/scalajvm/sttp/client4/quick.scala b/core/src/main/scalajvm/sttp/client4/quick.scala index 53f7595b1b..97123c35b2 100644 --- a/core/src/main/scalajvm/sttp/client4/quick.scala +++ b/core/src/main/scalajvm/sttp/client4/quick.scala @@ -1,9 +1,7 @@ package sttp.client4 -import sttp.client4.httpclient.HttpClientSyncBackend - object quick extends SttpApi { - lazy val backend: SyncBackend = HttpClientSyncBackend() + lazy val backend: SyncBackend = DefaultSyncBackend() implicit class RichRequest[T](val request: Request[T]) { def send(): Response[T] = backend.send(request) diff --git a/core/src/main/scalanative/sttp/client4/DefaultSyncBackend.scala b/core/src/main/scalanative/sttp/client4/DefaultSyncBackend.scala new file mode 100644 index 0000000000..d613cdd72c --- /dev/null +++ b/core/src/main/scalanative/sttp/client4/DefaultSyncBackend.scala @@ -0,0 +1,13 @@ +package sttp.client4 + +import sttp.client4.curl.CurlBackend +import sttp.client4.testing.SyncBackendStub + +object DefaultSyncBackend { + + /** Creates a default synchronous backend, which is currently based on [[CurlBackend]]. */ + def apply(): SyncBackend = CurlBackend() + + /** Create a stub backend for testing. See [[SyncBackendStub]] for details on how to configure stub responses. */ + def stub: SyncBackendStub = SyncBackendStub +} diff --git a/core/src/main/scalanative/sttp/client4/quick.scala b/core/src/main/scalanative/sttp/client4/quick.scala index e76982d5c8..97123c35b2 100644 --- a/core/src/main/scalanative/sttp/client4/quick.scala +++ b/core/src/main/scalanative/sttp/client4/quick.scala @@ -1,9 +1,7 @@ package sttp.client4 -import sttp.client4.curl.CurlBackend - object quick extends SttpApi { - lazy val backend: SyncBackend = CurlBackend() + lazy val backend: SyncBackend = DefaultSyncBackend() implicit class RichRequest[T](val request: Request[T]) { def send(): Response[T] = backend.send(request) diff --git a/docs/backends/summary.md b/docs/backends/summary.md index 476b98c2c4..af24513f92 100644 --- a/docs/backends/summary.md +++ b/docs/backends/summary.md @@ -4,17 +4,24 @@ sttp supports a number of synchronous and asynchronous backends. It's the backen Choosing the right backend depends on a number of factors: whether you are using sttp to explore some data, or is it a production system; are you using a synchronous, blocking architecture, or an asynchronous one; do you work mostly with Scala's `Future`, or maybe you use some form of a `Task` abstraction; finally, if you want to stream requests/responses, or not. -Which one to choose? +## Default backends -* for simple exploratory requests, use the [synchronous](synchronous.md) `HttpClientSyncBackend`. -* if you have Akka in your stack, use the [Akka backend](akka.md) -* if you are using `Future` without Akka, use the `HttpClientFutureBackend` -* finally, if you are using a functional effect wrapper, use one of the "functional" backends, for [ZIO](zio.md), [Monix](monix.md), [Scalaz](scalaz.md), [cats-effect](catseffect.md) or [fs2](fs2.md). +As a starting point, the default backends are good choice. Depending on the platform, the following are available: + +* on the JVM, `DefaultSyncBackend` and `DefaultFutureBackend`: both based on Java's HTTP client +* on JS, `DefaultFutureBackend`, based on Fetch +* on Native, `DefaultSyncBackend`, based on curl -Each backend has two type parameters: +These default backends provide limited customisation options, hence for any more advanced use-cases, simply substitute them with a specific implementation. E.g. the `HttpClientSyncBackend` backend, which is the underlying implementation of `DefaultSyncBackend`, offers customisation options not available in the default one. + +## Backends overview + +Which one to choose? -* `F[_]`, the effects wrapper for responses. That is, when you invoke `send(backend)` on a request description, do you get a `Response[_]` directly, or is it wrapped in a `Future` or a `Task`? -* `P`, the capabilities supported by the backend, in addition to `Effect[F]`. If `Any`, no additional capabilities are provided. Might include `Streams` (the ability to send and receive streaming bodies) and `WebSockets` (the ability to handle websocket requests). +* for simple exploratory requests, use the [synchronous](synchronous.md) `DefaultSyncBackend` / `HttpClientSyncBackend`. +* if you have Akka in your stack, use the [Akka backend](akka.md) +* if you are using `Future` without Akka, use the `DefaultFutureBackend` / `HttpClientFutureBackend` +* finally, if you are using a functional effect wrapper, use one of the "functional" backends, for [ZIO](zio.md), [Monix](monix.md), [Scalaz](scalaz.md), [cats-effect](catseffect.md) or [fs2](fs2.md). Below is a summary of all the JVM backends; see the sections on individual backend implementations for more information: @@ -22,7 +29,9 @@ Below is a summary of all the JVM backends; see the sections on individual backe ==================================== ================================ ================================================= ========================== =================== Class Effect type Supported stream type Supports websockets Fully non-blocking ==================================== ================================ ================================================= ========================== =================== +``DefaultSyncBackend`` None (``Identity``) n/a no no ``HttpClientSyncBackend`` None (``Identity``) n/a no no +``DefaultFutureBackend`` ``scala.concurrent.Future`` n/a yes (regular) no ``HttpClientFutureBackend`` ``scala.concurrent.Future`` n/a yes (regular) no ``HttpClientMonixBackend`` ``monix.eval.Task`` ``monix.reactive.Observable[ByteBuffer]`` yes (regular & streaming) yes ``HttpClientFs2Backend`` ``F[_]: cats.effect.Concurrent`` ``fs2.Stream[F, Byte]`` yes (regular & streaming) yes @@ -50,7 +59,7 @@ Class Effect type Supported ==================================== ================================ ================================================= ========================== =================== ``` -The backends work with Scala 2.11, 2.12, 2.13 and 3 (with some exceptions for 2.11 and 3). +The backends work with Scala 2.12, 2.13 and 3. Backends supporting cats-effect are available in versions for cats-effect 2.x (dependency artifacts have the `-ce2` suffix) and 3.x. @@ -59,6 +68,7 @@ All backends that support asynchronous/non-blocking streams, also support server There are also backends which wrap other backends to provide additional functionality. These include: * `TryBackend`, which safely wraps any exceptions thrown by a synchronous backend in `scala.util.Try` +* `EitherBackend`, which represents exceptions as the left side of an `Either` * `OpenTelemetryTracingBackend`, for OpenTelemetry-compatible distributed tracing. See the [dedicated section](wrappers/opentelemetry.md). * `OpenTelemetryMetricsBackend`, for OpenTelemetry-compatible metrics. See the [dedicated section](wrappers/opentelemetry.md). * `PrometheusBackend`, for gathering Prometheus-format metrics. See the [dedicated section](wrappers/prometheus.md). @@ -73,6 +83,7 @@ In addition, there are also backends for Scala.JS: ================================ ================================ ========================================= =================== Class Effect type Supported stream type Supports websockets ================================ ================================ ========================================= =================== +``DefaultFutureBackend`` ``scala.concurrent.Future`` n/a yes (regular) ``FetchBackend`` ``scala.concurrent.Future`` n/a yes (regular) ``FetchMonixBackend`` ``monix.eval.Task`` ``monix.reactive.Observable[ByteBuffer]`` yes (regular & streaming) ``FetchZioBackend`` ``zio.Task`` ``zio.stream.Stream[Throwable, Byte]`` yes (regular & streaming) @@ -86,6 +97,7 @@ And a backend for scala-native: ================================ ============================ ========================================= =================== Class Effect type Supported stream type Supports websockets ================================ ============================ ========================================= =================== +``DefaultSyncBackend`` None (``Identity``) n/a no ``CurlBackend`` None (``Identity``) n/a no ================================ ============================ ========================================= =================== ``` @@ -94,4 +106,19 @@ Finally, there are third-party backends: * [sttp-play-ws](https://github.com/scalamania/sttp-play-ws) for "standard" play-ws (not standalone). * [akkaMonixSttpBackend](https://github.com/fullfacing/akkaMonixSttpBackend), an Akka-based backend, but using Monix's `Task` & `Observable`. -* [be-kind-rewind](https://github.com/reibitto/be-kind-rewind), a VCR testing library for Scala \ No newline at end of file +* [be-kind-rewind](https://github.com/reibitto/be-kind-rewind), a VCR testing library for Scala + +## Backend types + +Depending on the capabilities that a backend supports, the exact backend type differs: + +* `SyncBackend` are backends which are synchronous, blocking, and don't support streaming. +* `Backend[F]` are backends which don't support streaming or web sockets, and use `F` to represent side effects (e.g. obtaining a response for a request) +* `StreamBackend[F, S]` are backends which support streaming, use `F` to represent side effects, and `S` to represent streams of bytes. +* `WebSocketBackend[F]` are backends which support web sockets, use `F` to represent side effects +* `WebSocketStreamBackend[F, S]` are backends which support web sockets and streaming, use `F` to represent side effects, and `S` to represent streams of bytes. + +Each backend type extends `GenericBackend` has two type parameters: + +* `F[_]`, the type constructor used to represent side effects. That is, when you invoke `send(backend)` on a request description, do you get a `Response[_]` directly, or is it wrapped in a `Future` or a `Task`? +* `P`, the capabilities supported by the backend, in addition to `Effect[F]`. If `Any`, no additional capabilities are provided. Might include `Streams` (the ability to send and receive streaming bodies) and `WebSockets` (the ability to handle websocket requests). \ No newline at end of file diff --git a/docs/backends/wrappers/logging.md b/docs/backends/wrappers/logging.md index d4c0af7f39..36c7ab61d5 100644 --- a/docs/backends/wrappers/logging.md +++ b/docs/backends/wrappers/logging.md @@ -37,10 +37,9 @@ Example usage: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.logging.slf4j.Slf4jLoggingBackend -val backend = Slf4jLoggingBackend(HttpClientSyncBackend()) +val backend = Slf4jLoggingBackend(DefaultSyncBackend()) basicRequest.get(uri"https://httpbin.org/get").send(backend) // Logs: diff --git a/docs/conf/proxy.md b/docs/conf/proxy.md index be3ade4489..3d0793829a 100644 --- a/docs/conf/proxy.md +++ b/docs/conf/proxy.md @@ -14,9 +14,8 @@ Otherwise, proxy values can be specified manually when creating a backend: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend = HttpClientSyncBackend( +val backend = DefaultSyncBackend( options = BackendOptions.httpProxy("some.host", 8080)) basicRequest diff --git a/docs/conf/redirects.md b/docs/conf/redirects.md index a4e352d4fd..4e6770f0df 100644 --- a/docs/conf/redirects.md +++ b/docs/conf/redirects.md @@ -34,10 +34,9 @@ You can disable the stripping of all sensitive headers using the following code: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.wrappers.{FollowRedirectsBackend, FollowRedirectsConfig} -val myBackend: SyncBackend = HttpClientSyncBackend() +val myBackend: SyncBackend = DefaultSyncBackend() val backend: SyncBackend = FollowRedirectsBackend( delegate = myBackend, FollowRedirectsConfig( @@ -51,10 +50,9 @@ If you just want to disable stripping of the `Authorization` header, you can do ```scala mdoc:compile-only import sttp.client4._ import sttp.model._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.wrappers.{FollowRedirectsBackend, FollowRedirectsConfig} -val myBackend: SyncBackend = HttpClientSyncBackend() +val myBackend: SyncBackend = DefaultSyncBackend() val backend: SyncBackend = FollowRedirectsBackend( delegate = myBackend, FollowRedirectsConfig( @@ -103,11 +101,10 @@ For example: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.wrappers.{FollowRedirectsBackend, FollowRedirectsConfig} import sttp.model.Uri.QuerySegmentEncoding -val myBackend: SyncBackend = HttpClientSyncBackend() +val myBackend: SyncBackend = DefaultSyncBackend() val backend: SyncBackend = FollowRedirectsBackend( delegate = myBackend, FollowRedirectsConfig( diff --git a/docs/conf/timeouts.md b/docs/conf/timeouts.md index 2bc106ca42..d4442e327a 100644 --- a/docs/conf/timeouts.md +++ b/docs/conf/timeouts.md @@ -9,11 +9,10 @@ How to use: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import scala.concurrent.duration._ // all backends provide a constructor that allows to specify backend options -val backend = HttpClientSyncBackend( +val backend = DefaultSyncBackend( options = BackendOptions.connectionTimeout(1.minute)) basicRequest diff --git a/docs/how.md b/docs/how.md index a4557139b1..f889bc2744 100644 --- a/docs/how.md +++ b/docs/how.md @@ -31,9 +31,8 @@ For example, the following sends a synchronous request, using the default JVM ba ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend val myRequest: Request[String] = ??? -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val response = myRequest.send(backend) ``` diff --git a/docs/index.md b/docs/index.md index e83dd1e130..71d669f1a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,15 +3,14 @@ Welcome! [sttp client](https://github.com/softwaremill/sttp) is an open-source library which provides a clean, programmer-friendly API to describe HTTP -requests and how to handle responses. Requests are sent using one of the backends, which wrap other Scala or Java HTTP client implementations. The backends can integrate with a variety of Scala stacks, providing both synchronous and asynchronous, procedural and functional interfaces. - -Backend implementations include ones based on [akka-http](https://doc.akka.io/docs/akka-http/current/scala/http/), [http4s](https://http4s.org), [OkHttp](http://square.github.io/okhttp/), and HTTP clients which ship with Java. They integrate with [Akka](https://akka.io), [Monix](https://monix.io), [fs2](https://github.com/functional-streams-for-scala/fs2), [cats-effect](https://github.com/typelevel/cats-effect), [scalaz](https://github.com/scalaz/scalaz) and [ZIO](https://github.com/zio/zio). Supported Scala versions include 2.11, 2.12, 2.13 and 3, Scala.JS and Scala Native. +requests and how to handle responses. Requests are sent using one of the backends, which wrap lower-level Scala or Java HTTP client implementations. The backends can integrate with a variety of Scala stacks, providing both synchronous and asynchronous, procedural and functional interfaces. + +Backend implementations include the HTTP client that is shipped with Java, as well as ones based on [akka-http](https://doc.akka.io/docs/akka-http/current/scala/http/), [http4s](https://http4s.org), [OkHttp](http://square.github.io/okhttp/). They integrate with [Akka](https://akka.io), [Monix](https://monix.io), [fs2](https://github.com/functional-streams-for-scala/fs2), [cats-effect](https://github.com/typelevel/cats-effect), [scalaz](https://github.com/scalaz/scalaz) and [ZIO](https://github.com/zio/zio). Supported Scala versions include 2.12, 2.13 and 3, Scala.JS and Scala Native; supported Java versions include 11+. Here's a quick example of sttp client in action: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend val query = "http language:scala" val sort: Option[String] = None @@ -21,7 +20,7 @@ val sort: Option[String] = None val request = basicRequest.get( uri"https://api.github.com/search/repositories?q=$query&sort=$sort") -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val response = request.send(backend) // response.header(...): Option[String] diff --git a/docs/json.md b/docs/json.md index 96804031c8..4108377cef 100644 --- a/docs/json.md +++ b/docs/json.md @@ -45,9 +45,8 @@ Response can be parsed into json using `asJson[T]`, provided there's an implicit ```scala mdoc:compile-only import sttp.client4._ import sttp.client4.circe._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() import io.circe.generic.auto._ val requestPayload = RequestPayload("some data") @@ -80,9 +79,8 @@ Usage example: ```scala mdoc:compile-only import sttp.client4._ import sttp.client4.json4s._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() val requestPayload = RequestPayload("some data") @@ -111,11 +109,10 @@ Usage example: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.sprayJson._ import spray.json._ -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() implicit val payloadJsonFormat: RootJsonFormat[RequestPayload] = ??? implicit val myResponseJsonFormat: RootJsonFormat[ResponsePayload] = ??? @@ -163,11 +160,10 @@ Usage example: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.ziojson._ import zio.json._ -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() implicit val payloadJsonEncoder: JsonEncoder[RequestPayload] = DeriveJsonEncoder.gen[RequestPayload] implicit val myResponseJsonDecoder: JsonDecoder[ResponsePayload] = DeriveJsonDecoder.gen[ResponsePayload] @@ -204,11 +200,10 @@ Usage example: ```scala mdoc:compile-only import sttp.client4._ import sttp.client4.jsoniter._ -import sttp.client4.httpclient.HttpClientSyncBackend import com.github.plokhotnyuk.jsoniter_scala.core._ import com.github.plokhotnyuk.jsoniter_scala.macros._ -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() implicit val payloadJsonCodec: JsonValueCodec[RequestPayload] = JsonCodecMaker.make //note that the jsoniter doesn't support 'implicit defs' and so either has to be generated seperatly @@ -242,11 +237,10 @@ Usage example: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.upicklejson._ import upickle.default._ -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() implicit val requestPayloadRW: ReadWriter[RequestPayload] = macroRW[RequestPayload] implicit val responsePayloadRW: ReadWriter[ResponsePayload] = macroRW[ResponsePayload] diff --git a/docs/model/model.md b/docs/model/model.md index 4780163bfd..24231f53a9 100644 --- a/docs/model/model.md +++ b/docs/model/model.md @@ -22,14 +22,13 @@ Example with objects: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.model._ object Example { val request = basicRequest.header(Header.contentType(MediaType.ApplicationJson)) .get(uri"https://httpbin.org") - val backend = HttpClientSyncBackend() + val backend = DefaultSyncBackend() val response = request.send(backend) if (response.code == StatusCode.Ok) println("Ok!") } @@ -39,14 +38,13 @@ Example with traits: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.model._ object Example extends HeaderNames with MediaTypes with StatusCodes { val request = basicRequest.header(ContentType, ApplicationJson.toString) .get(uri"https://httpbin.org") - val backend = HttpClientSyncBackend() + val backend = DefaultSyncBackend() val response = request.send(backend) if (response.code == Ok) println("Ok!") } diff --git a/docs/quickstart.md b/docs/quickstart.md index 585bce9790..3729db68a8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,10 +1,11 @@ # Quickstart -The core sttp client API comes in a single jar, with a transitive dependency on [sttp model](https://github.com/softwaremill/sttp-model). This also includes [synchronous](backends/synchronous.md) and [`Future`-based] backends, based on Java's `HttpClient`. +The core sttp client API comes in a single jar, with a transitive dependency on [sttp model](https://github.com/softwaremill/sttp-model). +This also includes [synchronous](backends/synchronous.md) and [`Future`-based] backends, based on Java's `HttpClient`. -To integrate with other parts of your application and various effect systems, you'll often need to use an alternate backend (but what's important is that the API remains the same!). See the section on [backends](backends/summary.md) for a short guide on which backend to choose, and a list of all implementations. +To integrate with other parts of your application and various effect systems, you'll often need to use an alternate backend, or backend wrappers (but what's important is that the API remains the same!). See the section on [backends](backends/summary.md) for a short guide on which backend to choose, and a list of all implementations. -`sttp client` is available for Scala 2.11, 2.12 and 2.13, as well as for Scala 3 and requires Java 11 or higher. +`sttp client` is available for Scala 2.12 and 2.13, as well as for Scala 3 and requires Java 11 or higher. `sttp client` is also available for Scala.js 1.0 and Scala Native. Note that not all modules are compatible with these platforms, and that each has its own dedicated set of backends. @@ -50,7 +51,7 @@ And that's all you need to start using sttp client! To create and send your firs ```scala import sttp.client4._ -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val response = basicRequest .body("Hello, world!") .post(uri"https://httpbin.org/post?hello=world") @@ -78,11 +79,10 @@ Your code might then look as follows: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.upicklejson._ import upickle.default._ -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() case class MyRequest(field1: String, field2: Int) // selected fields from the JSON that is being returned by httpbin @@ -116,18 +116,18 @@ Then, you'll need to configure your client: ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.logging.slf4j.Slf4jLoggingBackend -val backend = Slf4jLoggingBackend(HttpClientSyncBackend()) +val backend = Slf4jLoggingBackend(DefaultSyncBackend()) ``` ## Even quicker You can skip the step of creating a backend instance, by using `import sttp.client4.quick._` instead of the usual `import sttp.client4._`. This brings into scope the same sttp API, and additionally a synchronous backend instance, which can be used to send requests. +This backend instance is global (created on first access), can't be customised and shouldn't be closed. -Then, the `send()` extension method allows sending requests using that `backend` instance: +The `send()` extension method allows sending requests using that `backend` instance: ```scala mdoc:compile-only import sttp.client4.quick._ diff --git a/docs/requests/authentication.md b/docs/requests/authentication.md index ebc17cb660..3ceffbf6ab 100644 --- a/docs/requests/authentication.md +++ b/docs/requests/authentication.md @@ -30,10 +30,9 @@ This type of authentication works differently. In its assumptions it is based on In order to add digest authentication support just wrap other backend as follows: ```scala mdoc:compile-only -import sttp.client4.httpclient.HttpClientSyncBackend import sttp.client4.wrappers.DigestAuthenticationBackend -val myBackend: SyncBackend = HttpClientSyncBackend() +val myBackend: SyncBackend = DefaultSyncBackend() DigestAuthenticationBackend(myBackend) ``` @@ -68,7 +67,6 @@ You can use sttp with OAuth2. Looking at the [OAuth2 protocol flow](https://tool 2. (C)/(D) - You need to send a request to the authentication server, passing in the authentication code from step 1. You'll receive an access token in response (and optionally a refresh token). For example, if you were using GitHub as your authentication server, you'd need to take the values of `clientId` and `clientSecret` from the GitHub settings, then take the `authCode` received in step 1 above, and send a request like this: ```scala mdoc:compile-only import sttp.client4.circe._ -import sttp.client4.httpclient.HttpClientSyncBackend import io.circe._ import io.circe.generic.semiauto._ @@ -77,7 +75,7 @@ val clientId = "myClient123" val clientSecret = "s3cret" case class MyTokenResponse(access_token: String, scope: String, token_type: String, refresh_token: Option[String]) implicit val tokenResponseDecoder: Decoder[MyTokenResponse] = deriveDecoder[MyTokenResponse] -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val tokenRequest = basicRequest .post(uri"https://github.com/login/oauth/access_token?code=$authCode&grant_type=authorization_code") diff --git a/docs/requests/basics.md b/docs/requests/basics.md index 8a5b1f155f..0603e41bed 100644 --- a/docs/requests/basics.md +++ b/docs/requests/basics.md @@ -36,10 +36,8 @@ A request definition can be created without knowing how it will be sent. But to To invoke the `send(backend)` method on a request description, you'll need an instance of `SttpBackend`: ```scala mdoc:compile-only -import sttp.client4.httpclient.HttpClientSyncBackend - -val backend = HttpClientSyncBackend() -val response: Identity[Response[Either[String, String]]] = request.send(backend) +val backend = DefaultSyncBackend() +val response: Response[Either[String, String]] = request.send(backend) ``` The default backend uses the `Identity` effect to return responses, which is equivalent to a synchronous call (no effect at all). Other asynchronous backends use other effect types. See the section on [backends](../backends/summary.md) for more details. diff --git a/docs/requests/cookies.md b/docs/requests/cookies.md index 8102530687..8441e91f36 100644 --- a/docs/requests/cookies.md +++ b/docs/requests/cookies.md @@ -23,9 +23,8 @@ It is often necessary to copy cookies from a response, e.g. after a login reques ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val loginRequest = basicRequest .cookie("login", "me") .body("This is a test") @@ -39,9 +38,8 @@ Or, it's also possible to store only the `sttp.model.CookieWithMeta` objects (a ```scala mdoc:compile-only import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val loginRequest = basicRequest .cookie("login", "me") .body("This is a test") diff --git a/docs/responses/basics.md b/docs/responses/basics.md index 8510bb768d..2d88fdbf50 100644 --- a/docs/responses/basics.md +++ b/docs/responses/basics.md @@ -21,9 +21,8 @@ Individual headers can be obtained using the methods: ```scala mdoc:silent import sttp.model._ import sttp.client4._ -import sttp.client4.httpclient.HttpClientSyncBackend -val backend = HttpClientSyncBackend() +val backend = DefaultSyncBackend() val request = basicRequest .get(uri"https://httpbin.org/get") val response = request.send(backend) diff --git a/docs/testing.md b/docs/testing.md index 0b9646f0b1..354880b641 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -229,10 +229,8 @@ BackendStub(implicitly[MonadAsyncError[IO]]) It is also possible to create a stub backend which delegates calls to another (possibly "real") backend if none of the specified predicates match a request. This can be useful during development, to partially stub a yet incomplete API with which we integrate: ```scala mdoc:compile-only -import sttp.client4.httpclient.HttpClientSyncBackend - val testingBackend = - SyncBackendStub.withFallback(HttpClientSyncBackend()) + SyncBackendStub.withFallback(DefaultSyncBackend()) .whenRequestMatches(_.uri.path.startsWith(List("a"))) .thenRespond("I'm a STUB!") diff --git a/docs/xml.md b/docs/xml.md index 27a7ea522c..f6d5ee58a5 100644 --- a/docs/xml.md +++ b/docs/xml.md @@ -51,7 +51,7 @@ From now on, XML serialization/deserialization would work for all classes genera Usage example: ```scala -val backend: SyncBackend = HttpClientSyncBackend() +val backend: SyncBackend = DefaultSyncBackend() val requestPayload = Outer(Inner(42, b = true, "horses"), "cats") // `Outer` and `Inner` classes are generated by scalaxb from xsd file import sttpScalaxb._ // imports sttp related serialization / deserialization logic