FetchZioBackend and websockets

Hello, I’m probably doing something wrong while trying to use sttp (3.8.5) from scala.js (1.12.0) with websockets using FetchZioBackend, in the two situations I’ve tested, I got each time the following error message : sttp.client3.ws.GotAWebSocketException: Got a web socket, but expected normal content, although the web socket endpoint is working fine.

I’ve checked again the documentation, and it is said that FetchZioBackend supports websockets, so I wonder, do I have to add some configuration in order to enable websockets ?

The scala.js code looks like :

  val backend = FetchZioBackend()

  def processWebsocket(ws: WebSocket[Task]):Task[Unit] = {
    val receiveOne = ws.receiveText().flatMap(res => Console.printLine(s"received $res"))
    receiveOne.forever
  }

  def byHandWebsocketCall() = {
    val request =
      basicRequest
        .get(uri"ws://127.0.0.1:3000/ws/system/events")
        .response(asWebSocket(processWebsocket))

    val response =
      request
        .send(backend)

    Unsafe.unsafe { implicit u =>
      runtime.unsafe.fork {
         response
           .tap(result => Console.printLine(result.toString))
           .tapError(err => Console.printLine(s"--------> $err"))
      }
    }
  }

If I test the same websocket endpoint using scala/JVM I didn’t have any issue, consider this scala-cli code which uses HttpClientZioBackend :

//> using scala  "3.2.1"
//> using lib "dev.zio::zio:2.0.5"
//> using lib "com.softwaremill.sttp.client3::zio:3.8.5"

import zio.*
import sttp.client3.*, sttp.client3.basicRequest.*, sttp.ws.*

object WebSocketCat extends ZIOAppDefault {
  def processWebsocket(ws: WebSocket[Task]): Task[Unit] = {
    val receiveOne = ws.receiveText().flatMap(res => Console.printLine(s"received $res"))
    val sendOne    = Console.readLine.flatMap(line => ws.sendText(s"""{"message":"$line"}"""))
    receiveOne.forever.race(sendOne.forever)
  }

  def run =
    for {
      backend  <- sttp.client3.httpclient.zio.HttpClientZioBackend()
      response <- basicRequest
                    .get(uri"ws://127.0.0.1:3000/ws/system/events")
                    .response(asWebSocket(processWebsocket))
                    .send(backend)
    } yield response
}

WebSocketCat.main(Array.empty)

I first thought it was a tapir issue, as my first attemps was tapir based (with sttp of course behind the scene), I’ve opened this ticket (websocket client endpoint GotAWebSocketException exception with http4s and ZIO · Issue #2584 · softwaremill/tapir · GitHub), but after taking a look to this conference : Functional WebSockets - Adam Warski - YouTube I decided to make a new attempt using a more direct approach, and I got exactly the same issue.

Let’s move this over to this sttp issue to centralise the discussion :slight_smile: