Using Graphiql with Absinthe - unexpected web socket message

I’m using absinthe 1.4.10,absinthe_phoenix 1.4.2, and phoenix 1.3.2.

I want to define a GraphQL subscription that is implemented through a Phoenix channel as described by the readme in the absinthe_phoenix documentation. I believe I have followed all the steps there, but would be happy to learn that I have misconfigured something if I need to change it.

I am trying to use the Absinthe.Plug.GraphiQL tool as a means of testing my subscription. When I connect to my Phoenix application using the web interface it puts up, the channel receives an unexpected message which causes a crash:

** (exit) exited in: Phoenix.Endpoint.CowboyWebSocket.resume()
    ** (EXIT) an exception was raised:
        ** (MatchError) no match of right hand side value: %{"payload" => %{}, "type" => "connection_init"}
            (phoenix) lib/phoenix/transports/v2/websocket_serializer.ex:34: Phoenix.Transports.V2.WebSocketSerializer.decode!/2
            (yeti_web) lib/yeti_web/channels/user_socket.ex:4: YetiWeb.Serializer.decode!/2
            (phoenix) lib/phoenix/transports/websocket.ex:121: Phoenix.Transports.WebSocket.ws_handle/3
            (phoenix) lib/phoenix/endpoint/cowboy_websocket.ex:77: Phoenix.Endpoint.CowboyWebSocket.websocket_handle/3
            (cowboy) /Users/sthompson/Library/Mobile Documents/com~apple~CloudDocs/Projects/Elixir/yeti/deps/cowboy/src/cowboy_websocket.erl:588: :cowboy_websocket.handler_call/7
            (phoenix) lib/phoenix/endpoint/cowboy_websocket.ex:49: Phoenix.Endpoint.CowboyWebSocket.resume/3
            (cowboy) /Users/sthompson/Library/Mobile Documents/com~apple~CloudDocs/Projects/Elixir/yeti/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4

It appears that GraphiQL (or at least the underlying web socket client) is sending the message {"type":"connection_init","payload":{}} to the Phoenix socket and when Phoenix’s web socket serializer doesn’t find the fields required to convert a web socket message a message for a Phoenix Channel, it simply barfs.

I’m struggling now to understand at what level this message should be handled. It looks like it’s part of the Apollo GraphQL client libraries that are used by GraphiQL. If it is indeed a client-specific message then it’s not clear that cowboy, Absinthe or Phoenix should be handling it.

If it’s a GraphQL standard web socket message (which haven’t been able to nail down with my web searches) That would imply that it is a concern which should be handled at the Absinthe level.

It could also be a concern for Phoenix. I was expecting to find a point in the Phoenix socket handling for dealing with unexpected messages that come in through a Websocket (I anticipated finding something like GenServer’s handle_info where unrecognized web socket messages would land). I didn’t have any luck.

And finally, it IS a concern for my application as it is causing me to crash. I presume I could implement my own web socket handler for GraphQL subscriptions, but it would be awfully convenient to rely on Absinthe and Phoenix.

I would be happy to work with any of the Open Source projects in an effort to help resolve the issue. Can anyone suggest which project the problem should be handled in?

1 Like

OK. Further investigation has revealed this documentation:

GraphQL over WebSocket Protocol

Which suggests the protocol is tied to Apollo. I guess the question is “Is Apollo (client and server) the definitive implementation of GraphQL?”

Check out https://github.com/absinthe-graphql/absinthe-socket/tree/master/packages/socket-apollo-link

That appears to be client-side JavaScript. In this case I have not written the client… I’m using the the GraphiQL client as exposed by the Absinthe.Plug.GraphiQL plug and I’m working on the server.

OK. I believe the correct forum in which to address the issues I am having lie within the Absinthe community so I will take further discussion to the maintainers of that library and see if I can work with them to craft a solution.

Ideally the forum would be a good place to discuss this but you might have better luck in the #absinthe channel of the Elixir slack. I was recently playing with Absinthe and Phoenix and didn’t have any trouble with GraphiQL but I don’t have my system setup right now. I’m surprised you get an error even before you run any queries. Also I was using version 1.4.8 which appears to be retired now (not sure why) and I can’t find any changelog entries for 1.4.9 or 1.4.10.

In the Absinthe slack channel, @benwilson512 was able to spot the problem.

In spite of checking my code against the docs repeatedly, I had made two errors.

First at the point at which I forward the connection to Absinthe.Plug.GraphiQL I had not specified the socket:

    forward("/graphiql", Absinthe.Plug.GraphiQL,[
      schema: YetiWeb.Schema,
      socket: YetiWeb.UserSocket])  # <-- this line was missing

Secondly, in the actual GraphiQL interface itself, where it asked me for the web socket URL I had entered ws://localhost:4000/socket/websocket.

In general, that is the correct URL, but when you do put in the line I was missing above, then you don’t need the trailing “/websocket” (Presumably because the Phoenix JavaScript client will add it for you.

4 Likes

Now I have a server that will respond to subscription requests from a client that understands the web socket protocol of Phoenix Channels. This is a Good Thing™ For those client I have control over, I can use Phoenix Channels.

Unfortunately, my server will not respond properly to a client that uses any other web socket protocol. A notable one is the web socket protocol of the Apollo GraphQL client which, to me any way, seems to be the reference implementation (client and server) for much of the non-Phoenix GraphQL world :neutral_face:.

I may need to create a web socket handler that speaks the web socket protocol of Apollo and ties into Absinthe’s excellent framework. That will cover what I think are the majority of clients I’m likely to run into in the near future.

But as I said in the slack channel:

The next big client, with its own [web socket] protocol, could be right around the corner so being idealistic about absolute flexibility on my part is probably Unreasonable™ :disappointed:

1 Like

Thanks for reporting back on the forum and I’m glad that you got it sorted out :+1:

Also it would be great to have first-class support for the Apollo GraphQL client on top of Absinthe and yes, ideally Absinthe would be able to easily support any future clients as well.

Indeed, Absinthe itself has zero knowledge of Phoenix, so adding other transports is really just a matter of doing whatever is necessary for that transport and then calling Absinthe. Tools like Absinthe.Phoenix are just handy first class integrations with existing dominant toolchains.