Skip to content

Commit

Permalink
Examples, docs
Browse files Browse the repository at this point in the history
  • Loading branch information
adamw committed Jan 3, 2025
1 parent e05e465 commit 70a01d2
Show file tree
Hide file tree
Showing 29 changed files with 247 additions and 142 deletions.
2 changes: 2 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ lazy val examples = (projectMatrix in file("examples"))
libraryDependencies ++= Seq(
"io.circe" %% "circe-generic" % circeVersion,
"org.json4s" %% "json4s-native" % json4sVersion,
"com.github.plokhotnyuk.jsoniter-scala" %%% "jsoniter-scala-macros" % jsoniterVersion,
pekkoStreams,
logback
),
Expand All @@ -986,6 +987,7 @@ lazy val examples = (projectMatrix in file("examples"))
json4s,
circe,
upickle,
jsoniter,
scribeBackend,
slf4jBackend,
ox
Expand Down
13 changes: 7 additions & 6 deletions docs/backends/catseffect.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# cats-effect backend

The [Cats Effect](https://github.com/typelevel/cats-effect) backend is **asynchronous**.
It can be created for any type implementing the `cats.effect.Concurrent` typeclass, such as `cats.effect.IO`.
It can be created for any type implementing the `cats.effect.kernel.Async` typeclass, such as `cats.effect.IO`.
Sending a request is a non-blocking, lazily-evaluated operation and results in a wrapped response.
There's a transitive dependency on `cats-effect`.

Expand Down Expand Up @@ -82,9 +82,10 @@ Creation of the backend can be done in two basic ways:
Firstly, add the following dependency to your project:

```scala
"com.softwaremill.sttp.client4" %% "armeria-backend-cats" % "@VERSION@" // for cats-effect 3.x
// or
"com.softwaremill.sttp.client4" %% "armeria-backend-cats-ce2" % "@VERSION@" // for cats-effect 2.x
// for cats-effect 3.x
"com.softwaremill.sttp.client4" %% "armeria-backend-cats" % "@VERSION@"
// or for cats-effect 2.x
"com.softwaremill.sttp.client4" %% "armeria-backend-cats-ce2" % "@VERSION@"
```

create client:
Expand Down Expand Up @@ -126,8 +127,8 @@ val client = WebClient.builder("https://my-service.com")
val backend = ArmeriaCatsBackend.usingClient[IO](client)
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is build on top of [Armeria](https://armeria.dev/docs/client-http).
Expand Down
13 changes: 7 additions & 6 deletions docs/backends/fs2.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# fs2 backend

The [fs2](https://github.com/functional-streams-for-scala/fs2) backends are **asynchronous**. They can be created for any type implementing the `cats.effect.Async` typeclass, such as `cats.effect.IO`. Sending a request is a non-blocking, lazily-evaluated operation and results in a wrapped response. There's a transitive dependency on `cats-effect`.
The [fs2](https://github.com/functional-streams-for-scala/fs2) backends are **asynchronous**. They can be created for any type implementing the `cats.effect.kernel.Async` typeclass, such as `cats.effect.IO`. Sending a request is a non-blocking, lazily-evaluated operation and results in a wrapped response. There's a transitive dependency on `cats-effect`.

## Using HttpClient

Expand Down Expand Up @@ -77,9 +77,10 @@ Host header override is supported in environments running Java 12 onwards, but i
To use, add the following dependency to your project:

```scala
"com.softwaremill.sttp.client4" %% "armeria-backend-fs2" % "@VERSION@" // for cats-effect 3.x & fs2 3.x
// or
"com.softwaremill.sttp.client4" %% "armeria-backend-fs2" % "@VERSION@" // for cats-effect 2.x & fs2 2.x
// for cats-effect 3.x & fs2 3.x
"com.softwaremill.sttp.client4" %% "armeria-backend-fs2" % "@VERSION@"
// or for cats-effect 2.x & fs2 2.x
"com.softwaremill.sttp.client4" %% "armeria-backend-fs2" % "@VERSION@"
```

create client:
Expand Down Expand Up @@ -117,8 +118,8 @@ val client = WebClient.builder("https://my-service.com")
val backend = ArmeriaFs2Backend.usingClient[IO](client, dispatcher)
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is built on top of [Armeria](https://armeria.dev/docs/client-http).
Expand Down
4 changes: 2 additions & 2 deletions docs/backends/future.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ val client = WebClient.builder("https://my-service.com")
val backend = ArmeriaFutureBackend.usingClient(client)
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is build on top of [Armeria](https://armeria.dev/docs/client-http) and doesn't support host header override.
Expand Down
7 changes: 4 additions & 3 deletions docs/backends/http4s.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
This backend is based on [http4s](https://http4s.org) (client) and is **asynchronous**. To use, add the following dependency to your project:

```scala
"com.softwaremill.sttp.client4" %% "http4s-backend" % "@VERSION@" // for cats-effect 3.x & http4s 1.0.0-Mx
// or
"com.softwaremill.sttp.client4" %% "http4s-ce2-backend" % "@VERSION@" // for cats-effect 2.x & http4s 0.21.x
// for cats-effect 3.x & http4s 1.0.0-Mx
"com.softwaremill.sttp.client4" %% "http4s-backend" % "@VERSION@"
// or for cats-effect 2.x & http4s 0.21.x
"com.softwaremill.sttp.client4" %% "http4s-ce2-backend" % "@VERSION@"
```

The backend can be created in a couple of ways, e.g.:
Expand Down
4 changes: 2 additions & 2 deletions docs/backends/javascript/fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ val response: Task[Response[Observable[ByteBuffer]]] =
.send(backend)
```

```{eval-rst}
.. note:: Currently no browsers support passing a stream as the request body. As such, using the ``Fetch`` backend with a streaming request will result in it being converted into an in-memory array before being sent. Response bodies are returned as a "proper" stream.
```{note}
Currently no browsers support passing a stream as the request body. As such, using the `Fetch` backend with a streaming request will result in it being converted into an in-memory array before being sent. Response bodies are returned as a "proper" stream.
```

## Websockets
Expand Down
4 changes: 2 additions & 2 deletions docs/backends/monix.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ val client = WebClient.builder("https://my-service.com")
val backend = ArmeriaMonixBackend.usingClient(client)
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is build on top of [Armeria](https://armeria.dev/docs/client-http).
Expand Down
4 changes: 2 additions & 2 deletions docs/backends/scalaz.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ val client = WebClient.builder("https://my-service.com")
val backend = ArmeriaScalazBackend.usingClient(client)
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is build on top of [Armeria](https://armeria.dev/docs/client-http).
Expand Down
2 changes: 1 addition & 1 deletion docs/backends/start_stop.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ In case of most backends, you should only instantiate a backend once per applica

When ending the application, make sure to call `backend.close()`, which results in an effect which frees up resources used by the backend (if any). If the effect wrapper for the backend is lazily evaluated, make sure to include it when composing effects!

Note that only resources allocated by the backends are freed. For example, if you use the `AkkaHttpBackend()` the `close()` method will terminate the underlying actor system. However, if you have provided an existing actor system upon backend creation (`AkkaHttpBackend.usingActorSystem`), the `close()` method will be a no-op.
Note that only resources allocated by the backends are freed. For example, if you use the `PekkoHttpBackend()` the `close()` method will terminate the underlying actor system. However, if you have provided an existing actor system upon backend creation (`PekkoHttpBackend.usingActorSystem`), the `close()` method will be a no-op.
16 changes: 5 additions & 11 deletions docs/backends/synchronous.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,17 @@ Both HttpClient and OkHttp backends support regular [websockets](../other/websoc
"com.softwaremill.sttp.client4" %% "ox" % "@VERSION@",
```

```scala
import ox.*
import ox.channels.Source
```scala mdoc:compile-only
import sttp.client4.*
import sttp.client4.impl.ox.sse.OxServerSentEvents
import sttp.model.sse.ServerSentEvent
import java.io.InputStream

def handleSse(is: InputStream)(using IO): Unit =
supervised {
OxServerSentEvents.parse(is).foreach(event => println(s"Received event: $event"))
}
def handleSse(is: InputStream): Unit =
OxServerSentEvents.parse(is).foreach(event => println(s"Received event: $event"))

val backend = DefaultSyncBackend()
IO.unsafe:
basicRequest
.get(uri"https://postman-echo.com/server-events/3")
.response(asInputStreamAlways(handleSse))
.send(backend)
.response(asInputStreamAlways(handleSse))
.send(backend)
```
2 changes: 1 addition & 1 deletion docs/backends/wrappers/custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ class MyCustomBackendHttpTest extends HttpTest[Future]:
When implementing a backend wrapper using cats, it might be useful to import:

```scala
import sttp.client4.impl.cats.implicits._
import sttp.client4.impl.cats.implicits.*
```

from the cats integration module. The module should be available on the classpath after adding following dependency:
Expand Down
8 changes: 4 additions & 4 deletions docs/backends/zio.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ ArmeriaZioBackend.scoped().flatMap { backend => ??? }
ArmeriaZioBackend.usingDefaultClient().flatMap { backend => ??? }
```

```{eval-rst}
.. note:: The default client factory is reused to create `ArmeriaZioBackend` if a `SttpBackendOptions` is unspecified. So you only need to manage a resource when `SttpBackendOptions` is used.
```{note}
The default client factory is reused to create `ArmeriaZioBackend` if a `SttpBackendOptions` is unspecified. So you only need to manage a resource when `SttpBackendOptions` is used.
```

or, if you'd like to instantiate the [WebClient](https://armeria.dev/docs/client-http) yourself:
Expand All @@ -87,8 +87,8 @@ val client = WebClient.builder("https://my-service.com")
ArmeriaZioBackend.usingClient(client).flatMap { backend => ??? }
```

```{eval-rst}
.. note:: A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```{note}
A WebClient could fail to follow redirects if the WebClient is created with a base URI and a redirect location is a different URI.
```

This backend is build on top of [Armeria](https://armeria.dev/docs/client-http).
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

# General information about the project.
project = u'sttp'
copyright = u'2024, SoftwareMill'
copyright = u'2025, SoftwareMill'
author = u'SoftwareMill'

# The version info for the project you're documenting, acts as replacement for
Expand Down
2 changes: 1 addition & 1 deletion docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Each example is fully self-contained and can be run using [scala-cli](https://sc
to copy the content of the file, apart from scala-cli, no additional setup is required!). Hopefully this will make
experimenting with sttp client as frictionless as possible!

Examples are tagged with the stack being used (Direct-style, cats-effect, ZIO, Future) and backend implementation
Examples are tagged with the stack being used (direct-style, cats-effect, ZIO, Future) and backend implementation

```{eval-rst}
.. include:: includes/examples_list.md
Expand Down
2 changes: 1 addition & 1 deletion docs/other/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Arbitrary JSON structures can be traversed by parsing the result as `io.circe.Js

## Json4s

To encode and decode json using json4s, add the following dependency to your project:
To encode and decode json using json4s, add the following dependencies to your project:

```
"com.softwaremill.sttp.client4" %% "json4s" % "@VERSION@"
Expand Down
9 changes: 5 additions & 4 deletions docs/other/resilience.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ Still, the input for a particular resilience model might involve both the result

Here's an incomplete list of libraries which can be used to manage retries in various Scala stacks:

* for synchornous/direct-style: [ox](https://github.com/softwaremill/ox)
* for synchornous/direct-style: [Ox](https://github.com/softwaremill/ox)
* for `Future`: [retry](https://github.com/softwaremill/retry)
* for ZIO: [schedules](https://zio.dev/reference/schedule/), [rezilience](https://github.com/svroonland/rezilience)
* for Monix/cats-effect: [cats-retry](https://github.com/cb372/cats-retry)
* for Monix: `.restart` methods

sttp client contains a default implementation of a predicate, which allows deciding if a request is retriable: if the body can be sent multiple times, and if the HTTP method is idempotent.
This predicate is available as `RetryWhen.Default` and has type `(Request[_, _], Either[Throwable, Response[_]]) => Boolean`.
This predicate is available as `RetryWhen.Default` and has type `(GenericRequest[_, _], Either[Throwable, Response[_]]) => Boolean`.

See also the "retrying using ZIO" [example](../examples.md), as well as an example of a very simple [retrying backend wrapper](../backends/wrappers/custom.md).
See also the "resiliency" [examples](../examples.md), as well as an example of a very simple [retrying backend wrapper](../backends/wrappers/custom.md).

### Backend-specific retries

Expand All @@ -42,7 +42,8 @@ Some backends have built-in retry mechanisms:

## Rate limiting

* for akka-streams: [throttle in akka streams](https://doc.akka.io/docs/akka/current/stream/operators/Source-or-Flow/throttle.html)
* for synchornous/direct-style: [Ox](https://github.com/softwaremill/ox)
* for Akka Streams: [throttle in akka streams](https://doc.akka.io/docs/akka/current/stream/operators/Source-or-Flow/throttle.html)
* for ZIO: [rezilience](https://github.com/svroonland/rezilience)

## Java libraries
Expand Down
Loading

0 comments on commit 70a01d2

Please sign in to comment.