ghostdogpr / caliban

Functional GraphQL library for Scala
https://ghostdogpr.github.io/caliban/
Apache License 2.0
947 stars 248 forks source link

Caliban client: add support for subscriptions #236

Closed ghostdogpr closed 3 years ago

ghostdogpr commented 4 years ago

Currently Caliban Client only supports regular sttp requests. It would be nice to also offer a solution for subscriptions. Since it's a whole protocol and not just request/response, we need some wrapper around a websocket connection.

I suspect it will require usage of Ref, Queue and/or Stream so maybe we do a ZIO version and a cats-effect/fs2 one.

Note: there is no sttp backend for ScalaJS that supports WebSockets. See https://github.com/softwaremill/sttp/issues/432

schrepfler commented 4 years ago

A good start for a protocol would be the Apollo ws subscriptions project https://github.com/apollographql/subscriptions-transport-ws I've started a project where I wanted to implement just that but I wasn't aiming to make it too generic. If you want you can nick the case classes https://github.com/schrepfler/artemis though it's not functional or even tested to validate actual stream flow so I can't guarantee they're 100% correct.

ghostdogpr commented 4 years ago

@schrepfler yep, that protocol is what I implemented already on the server side and was intended to use for the client as well.

The main blocker for this issue is that I chose to capitalize on sttp for caliban-client (so that users could pick the backend of their choice), but there is no sttp backend that support WebSockets on Scala.js. If it never comes maybe I should use something else 🤔

schrepfler commented 4 years ago

Didn't they address this in sttp2? https://blog.softwaremill.com/websockets-in-scala-using-sttp-baefd207c5fb

ghostdogpr commented 4 years ago

@schrepfler Sadly not on Scala.js so far

ghostdogpr commented 3 years ago

https://github.com/softwaremill/sttp/issues/432 was resolved so it's not a blocker anymore

fdietze commented 3 years ago

Hi, what needs to be done to implement subscriptions? I might look into it.

ghostdogpr commented 3 years ago

@fdietze I think @paulpdaniels started working on it so we need to get his feedback first on what he did.

But the idea is to add something similar to toRequest that returns a stream of objects (properly parsed). This would take care of creating the graphql request (should be easy with existing code), create an sttp websocket request and implement the graphql ws transport protocol (https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) on top of it so that it's transparent for the user. Since it returns a stream, it should probably be a separate module (e.g. caliban-client-subscriptions-zio for ZIO Stream, or caliban-client-subscriptions-fs2 for fs2).

paulpdaniels commented 3 years ago

I have most of the protocol implemented I think, I was working on getting tests working though. I can push a PR this week though.

ghostdogpr commented 3 years ago

Sttp support for WebSockets isn't that great actually, there are still many things that are not supported with Scala.js.

For this reason, I decided to focus on a pure and elegant Scala.js solution and worked on support for Laminar. All the reusable code lives in caliban-client, and the integration itself is just a few lines of code. I believe thanks to this code as a baseline, anyone should be able to add support to their own code even if they use another library.

Here's the PR: https://github.com/ghostdogpr/caliban/pull/897