# Sttp client 4: improving the developer experience

**URL:** <https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94>\
**Category:** sttp client\
**Created:** [January 19, 2023, 9:20am UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94 "2023-01-19T09:20:28Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![adamw](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/adamw/32/28_2.png) [@adamw](https://softwaremill.community/u/adamw)\
**Post date:** [January 19, 2023, 9:20am UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/1 "2023-01-19T09:20:28Z")

</div>

[Adrien Piquerez](https://github.com/adpi2) created a thorough and [code-complete proposal](https://github.com/softwaremill/sttp/pull/1703) on overhauling sttp client’s `RequestT` and `SttpBackend` types, by splitting them into multiple traits/classes, and thus reducing the number of type parameters. This is of course a binary-incompatible change, and would have to form the basis of sttp version 4.

Using that occasion, I’d like to gather wider feedback not only on the proposal, but also on your experiences with learning and using sttp client.

Starting with learning, some questions that would be helpful for us to understand how to improve the developer experience when using sttp:

- what did you find most puzzling, when learning sttp?
- when explaining sttp to co-workers, what was hardest for them to grasp?
- which compiler messages have been misleading or not helpful?
- do you use IDE’s type inference for sttp’s data structures, and if so, does it work well for you? did you understand why a specific type was inferred, and what the type means?
- what was the largest road-block, that slowed you down when trying to make your first HTTP request using sttp?

Then, moving from learning to using sttp:

- what’s are some of your daily “gotchas” that you have to keep in mind, when working with sttp?
- is there any type of problem that surfaces again and again?
- considering type safety: which area could be more type-safe, preventing some common bugs that need testing to detect?
- how often do you define custom backend wrappers? do they work with a single, or multiple other backends / effect types / capabilities?
- do you leverage sttp’s capability of customising any request (both partial & with the method/uri specified) using a single method?

Finally: if you have any idea on improving the API (even if it seems wild and improbable) - that’s the place to share 🙂

Thank you!

---

<div class="post-metadata">

**Author:** ![Krever](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/krever/32/77_2.png) [@Krever](https://softwaremill.community/u/Krever)\
**Post date:** [January 19, 2023, 10:47am UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/2 "2023-01-19T10:47:25Z")

</div>

> - what did you find most puzzling, when learning sttp?

Websocket support, but this is (partially) gone from signatures now.

> - is there any type of problem that surfaces again and again?

response parsers (`asJson`). They are a bit complicated when you need to use anything more complicated. I cant give anything more precise at the moment but I remember fighting with them on couple occasions.

> - how often do you define custom backend wrappers? do they work with a single, or multiple other backends / effect types / capabilities?

We have some in many places, so relatively often. They typically need to work only with one underlying backend.

> - do you leverage sttp’s capability of customising any request (both partial & with the method/uri specified) using a single method?

you probably mean generic code that applies the same changes regardless of request completeness. If thats the case I can’t recall such code.

> Finally: if you have any idea on improving the API (even if it seems wild and improbable) - that’s the place to share 🙂

What I would love to have is ability to access raw response, regardless of what transformation where applied on top. Obviously this wont be possible for streams, but for most common case of strings/bytes being sent, this should be doable. We have an awkward `asBoth()` usage but we introduced some bugs when used not properly.

---

<div class="post-metadata">

**Author:** ![tabdulradi](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/tabdulradi/32/79_2.png) [@tabdulradi](https://softwaremill.community/u/tabdulradi)\
**Post date:** [January 19, 2023, 1:18pm UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/3 "2023-01-19T13:18:05Z")

</div>

> if you have any idea on improving the API

Middlewares as first class Tapir concept.  
Usecase: Distributed tracing middleware should be able to add the tracing headers to the docs.

Another thing I remember was challenging is to implement a monitoring http4s middleware that can figure out which endpoint is being hit so that it can increment the correct guage. It would be nice if Tapir Middleware would/could run after routing and has access to the endpoint object.

---

<div class="post-metadata">

**Author:** ![adamw](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/adamw/32/28_2.png) [@adamw](https://softwaremill.community/u/adamw)\
**Post date:** [January 19, 2023, 1:34pm UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/4 "2023-01-19T13:34:06Z")

</div>

> [@tabdulradi](#):
>
> Middlewares as first class Tapir concept.

That’s a different project, but good suggestion as well - maybe you could move this to the [tapir forum](https://softwaremill.community/c/tapir/5)?

I’ll also change the title to explicitly say it’s about the client, my bad 🙂

---

<div class="post-metadata">

**Author:** ![dpennell](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/dpennell/32/109_2.png) [@dpennell](https://softwaremill.community/u/dpennell)\
**Post date:** [January 19, 2023, 3:15pm UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/5 "2023-01-19T15:15:33Z")

</div>

> [@Krever](#):
>
> > response parsers (`asJson`). They are a bit complicated when you need to use anything more complicated. I cant give anything more precise at the moment but I remember fighting with them on couple occasions.

Ditto - especially for dealing with broken APIs. e.g. reply with JSON on errors most of the time, but occasionally send back a raw string.

> [@Krever](#):
>
> > What I would love to have is ability to access raw response, regardless of what transformation where applied on top. Obviously this wont be possible for streams, but for most common case of strings/bytes being sent, this should be doable. We have an awkward `asBoth()` usage but we introduced some bugs when used not properly.

Ditto. We find it difficult to debug deserialization errors (especially with zio-json where error messages only show the offending next character).

> what did you find most puzzling, when learning sttp?  
> The ZIO encoding with two separate error encodings. Most of the time `absolve` is fine, but new sttp users find this challenging.

> considering type safety: which area could be more type-safe, preventing some common bugs that need testing to detect?

the `uri` interpolator is seductive, but can easily generate bad uri’s (e.g. substituting something besides strings)

> Finally: if you have any idea on improving the API (even if it seems wild and improbable) - that’s the place to share 🙂

- We would like to see `RequestMetadata` included in `ResponseException`

---

<div class="post-metadata">

**Author:** ![guidoschmidt17](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/guidoschmidt17/32/66_2.png) [@guidoschmidt17](https://softwaremill.community/u/guidoschmidt17)\
**Post date:** [March 15, 2023, 3:01pm UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/6 "2023-03-15T15:01:18Z")

</div>

I just adopted our code to use 4.0.0-M1. I had to change just the imports and a few lines of code.

```auto
- private val backend: SttpBackend[Task, ZioStreams & WebSockets]
+ private val backend: WebSocketBackend[Task]
- def doConnect(uri: Uri, backend: SttpBackend[Task, ZioStreams & WebSockets], connection: Connection) 
+ def doConnect(uri: Uri, backend: WebSocketBackend[Task], connection: Connection)

```

All tests pass and also the benchmarks show no difference. So it looks very promising. Thx a lot.

---

<div class="post-metadata">

**Author:** ![ghostdogpr](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/ghostdogpr/32/143_2.png) [@ghostdogpr](https://softwaremill.community/u/ghostdogpr)\
**Post date:** [May 14, 2023, 10:10am UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/7 "2023-05-14T10:10:25Z")

</div>

Hi!

I am coming a bit late but there is something I have not been able to do with sttp and maybe sttp 4 could be a chance to address it.

In Caliban Client, I have a function to transform a graphQL query into an sttp request: creating the request with the proper body and method, then parsing the response (using `mapResponse`) to return a nice object rather than a String. Then users are able to run this sttp request with the backend of their choice. This is perfect!

Now, I would like to do the same thing with WebSockets. I’d like to have another function that will transform my graphQL query into an sttp websocket request, and that function would take care of sending some “initialization” message(s), and parsing the received messages into a nice object to return a stream of these objects to the user.  
I don’t think this is doable currently as `Streams` and `Pipe` do not expose anything. You have to choose a backend in order to do something, so the only way I can expose this function is to force the usage of a specific backend.

One interesting thing I saw is that in `WebSocketStreamingTest` there is a basic version of that since there is some generic code that requires a `functionToPipe` to be transformed into the proper backend `Pipe`.

Let me know if I missed something, or if this is something that could be solved.  
Thanks!

---

<div class="post-metadata">

**Author:** ![adamw](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/adamw/32/28_2.png) [@adamw](https://softwaremill.community/u/adamw)\
**Post date:** [May 23, 2023, 2:44pm UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/8 "2023-05-23T14:44:00Z")

</div>

Thanks! Definitely not too late, we’ve got to come back to sttp4 & API changes sometime soon 🙂

If I understand correctly, this is somewhat partly implemented in tapir, where you can provide codecs for requests & responses (though no initialization messages, so these are simple functions `LOW_LEVEL => HIGH_LEVEL`, not `Stream[LOW_LEVEL] => Stream[HIGH_LEVEL]`. So on the sttp client level, I suppose what you’d want is to be able to map the defined response’s stream? Would that work?

---

<div class="post-metadata">

**Author:** ![ghostdogpr](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/ghostdogpr/32/143_2.png) [@ghostdogpr](https://softwaremill.community/u/ghostdogpr)\
**Post date:** [May 24, 2023, 12:34am UTC](https://softwaremill.community/t/sttp-client-4-improving-the-developer-experience/94/9 "2023-05-24T00:34:16Z")

</div>

Map the response would be nice, but also send some request.

Actually I have an example showing exactly what I want. This is the integration with Laminar/Laminext: [caliban/package.scala at e1d2998a82378ec148714e09b586bee9c7023a15 · ghostdogpr/caliban · GitHub](https://github.com/ghostdogpr/caliban/blob/e1d2998a82378ec148714e09b586bee9c7023a15/client-laminext/src/main/scala/caliban/client/laminext/package.scala#L82-L94)

Basically I send some message through the WebSocket and return a stream of converted responses. Then end-users can simply run that and consume it. I’d like to do the same thing with sttp but without choosing a backend.
