I’ve been trying to write an Elixir GraphQL API without the use of Phoenix. I’ve been using Plug, Cowboy, and Absinthe as my stack.
I wanted to look into implementing subscriptions over websocket but could not find a documentation to do it. I can find the Understanding Subscriptions page in the docs, that says:
Like queries and mutations, subscriptions are not intrinsically tied to any particular transport, and they’re built within Absinthe itself to be able to operate on many different platforms.
But the documentation is only focused on Phoenix which is fine. However the documentation for Absinthe.Subscription.child_spec explicitly calls for a Phoenix.Pubsub.
Questions:
Is it really possible to use subscriptions without Phoenix?
Is there any documentation / example code that I could look at?
If there is no complete example code, could someone give me a few links that would guide me towards an implementation?
Has anyone done something like this?
Meanwhile I tried skimming through Crafting GraphQL APIs in Elixir with GraphQL, where it was mentioned that Subscriptions are not tied to Phoenix, and that the book explores them outside of the framework, but haven’t been able to find where that happens
If anyone knows where that happens that would be helpful as well!
Hey @blascsi. It’s true that the docs reference Phoenix a fair bit, as that’s generally what everybody is using. However if you checkout the Absinthe.Subscription.Pubsub — absinthe v1.7.1 behavior docs you’ll see that you could provide your own module that implements these callbacks, and the docs cover roughly what is expected of each callback.
Do you have an existing multi-node pubsub you want to use, or are you going to roll your own?
@blascsi, just in case you hadn’t noticed: Phoenix.PubSub, despite the name, is its own package that has no dependency on any part of the rest of Phoenix. phoenix_pubsub | Hex
I’ve been working on this over the weekend and hit a new roadblock.
I created a very simple websocket handler like this:
defmodule MyApp.SocketHandler do
@behaviour :cowboy_websocket
def init(req, state) do
{:cowboy_websocket, req, state}
end
def websocket_init(state) do
{:ok, state}
end
def websocket_handle(req, state) do
{:reply, req, state}
end
def websocket_info(info, state) do
{:reply, info, state}
end
def terminate(_reason, _req, _state) do
:ok
end
end
It does not do anything just upgrades the connections to WS, and echoes back the messages it gets. So far so good. I was trying to do this because I wanted to see the messages that Absinthe sends to the WS, and set up my Pubsub subscription that way. However all I’m seeing when I start the subscription from Graphiql is phx_join, phx_leave and phoenix pings over the socket.
Anyone knows how am I supposed to receive the query the client tries to execute? It’s not in the query parameters either.
If you’re doing Websockets as well as pubsub, you’re gonna be reinventing the Phoenix wheel a fair bit. I would seriously reconsider the choice to stick with just Plug. The Absinthe Phoenix JS libraries all assume you have Phoenix on hand.