ekobi

ekobi

Help implementing graphql-ws subprotocol support in Absinthe

Hi,

Many GraphQL clients implement subscriptions using the graphql-ws WebSockets subprotocol. I have been experimenting with adding support in Absinthe-based servers, and could use some help getting it over the finish line.

The basic idea is to define a separate mount point, e.g. /graphql-ws, which gets routed to a socket with a different JSON serializer:

  socket "/graphql-ws", GrapixDemo.UserSocket,
    websocket: [
      subprotocols: ["graphql-ws"],
      serializer: [{Grapix.GraphqlWS.V1.JSONSerializer, ">= 1.0.0"}]
    ],
    longpoll: false

What I can’t seem to figure out is how to inject the client-defined reference ID into the subscription data updates processed by fastlane!(%{Broadcast} = msg) in the serializer implementation:

  def fastlane!(%Broadcast{} = msg) do
    msg |> IO.inspect(label: "#{__MODULE__}/fastlane -- broadcast msg")

    # "1" should be client-defined refId
    data = phoenix2gql(nil, "1", msg.topic, msg.event, msg.payload.result)

    {:socket_push, :text, Phoenix.json_library().encode_to_iodata!(data)}
  end

I’m assuming that the Broadcast message omits the client-specific reference ID by design – it’s a broadcast, after all. But Absinthe clearly keeps track of per-client and per-subscription data with a unique topic:sub-topic identifier:

Elixir.Grapix.GraphqlWS.V1.JSONSerializer/fastlane -- broadcast msg: %Phoenix.Socket.Broadcast{
  event: "subscription:data",
  payload: %{
    result: %{
      data: %{
        "serviceStatus" => %{
          "__typename" => "ServiceStatus",
          "messages" => [
            %{
              "__typename" => "ServiceStatusMessage",
              "level" => "ADVISORY",
              "message" => "Wake up, dude!",
              "timestamp" => "2020-03-17T15:25:25.170999Z"
            }
          ]
        }
      }
    },
    subscriptionId: "__absinthe__:doc:73257102"
  },
  topic: "__absinthe__:doc:73257102"
}

Any thoughts on how to proceed? Thanks.

Where Next?

Popular in Questions Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement