AshGraphql Subscription - Why does the data do not show up on subscribe?

Hi,

I created an Ash application with the following:

  • AshGraphql
  • Subscription
  • AshSqlite

The issue is that the data does not show up in the graphiql interface. The issue can be reproduced with the reproduction repository.

Minimal Reproduction Repository

I followed the Video and the Guide here:

Found workaround - OpenAI codex found it…

Switch from simple GraphQL interface to playground - as the simple seem to not support the subscriptions:

I also provided here a quick guide on how to setup it from scratch

1 Like

I am still struggle with the Websocket subscription. I can not subscribe from external app like another react app - or my actual goal - from SwiftUI.

I have noticed that:

Works:
Interface :playground

Subscription

subscription PostCreated {
  postChanged {
    created {
      id
    	text
      text
    }
  }
}

Output in playground

{
  "data": {
    "postChanged": {
      "created": {
        "id": "01977fab-96d7-7d8a-bd31-c2a6cb4dc42d",
        "text": "Create Post"
      }
    }
  }
}

Output in browser console

[
    null,
    null,
    "__absinthe__:doc:",
    "subscription:data",
    {
        "result": {
            "data": {
                "postChanged": {
                    "created": {
                        "id": "01977fad-b7ea-7210-bea9-0c102811a77a",
                        "text": "Create Post"
                    }
                }
            }
        },
        "subscriptionId": "__absinthe__:doc:NDBuu9SaWIecvz5i9JO1q8t8pVxZNpzmkO5ZKzdfHxw=:A604DB20983D4EF98C369B525464A8023C4EB34291F6CDAC41CB20E481D3B2B6"
    }
]

From Postman
But when I try to connect from external tool like Postman (when connecting via the ws view on postman. I see error

Operation failed
23:01:48
Server sent no subprotocol
An error occurred with the WebSocket connection
23:01:48
Server sent no subprotocol
Handshake Details
Request Method: "GET"
Status Code: "101 Switching Protocols"
Request Headers
Sec-WebSocket-Version: "13"
Sec-WebSocket-Key: "HdTl8OncyDOMSGpq3lqhaQ=="
Connection: "Upgrade"
Upgrade: "websocket"
accept: "application/json"
content-type: "application/json"
Sec-WebSocket-Protocol: "graphql-ws"
user-agent: "PostmanClient/undefined (AppId=25983cc5-b338-491e-8e8b-799bb7bf37ae)"
Sec-WebSocket-Extensions: "permessage-deflate; client_max_window_bits"
Host: "localhost:4000"
Response Headers
date: "Tue, 17 Jun 2025 21:01:48 GMT"
upgrade: "websocket"
connection: "Upgrade"
sec-websocket-accept: "QERN/lfOJFzhnfB7E401vJgszSo="
cache-control: "max-age=0, private, must-revalidate"

When using the graphql view

Unexpected server response: 400
Handshake Details
Request Method: "GET"
Status Code: "400 Bad Request"
Request Headers
Sec-WebSocket-Version: "13"
Sec-WebSocket-Key: "wMy8ywB98auf9cR3WiMa1A=="
Connection: "Upgrade"
Upgrade: "websocket"
accept: "application/json"
content-type: "application/json"
Sec-WebSocket-Protocol: "graphql-ws"
user-agent: "PostmanClient/undefined (AppId=25983cc5-b338-491e-8e8b-799bb7bf37ae)"
Sec-WebSocket-Extensions: "permessage-deflate; client_max_window_bits"
Host: "localhost:4000"
Response Headers
date: "Tue, 17 Jun 2025 21:17:40 GMT"
content-length: "53"
vary: "accept-encoding"
cache-control: "max-age=0, private, must-revalidate"
x-request-id: "GEnxIqX_eofhF4sAAABD"
content-type: "application/json; charset=utf-8"

What’s the exact request? Maybe you’re missing ?vsn=2.0.0 which would specify Phoenix’s Channel Protocol. :thinking:

Check out this. :eyes: Maybe it could help.

Also you could try Altair GraphQL Client instead of Postman, could be easier in setup.

Thanks for your answer. To summarize:

My goal is to connect from a Swift App to my Elixir Ash Backend. I am using a playground to debug. I now tried it with Altair - it gives a lot of GraqhQL options.

(i did not check out Absinthe.Client - as this is not my use case)

Result of my debugging:

:playground: Works
Altair: Does not work

The difference in the log output is that with playground it logs the subscription. With Altair there is no such log (I marked it with THIS IS NOT LOGGED ON ALTAIR).

Debug Process

Branch: [Debug]
(GitHub - bastiW/my_subscription_app_sqlite at debug)
Start Server with mix phx.server

I added to my graphql_socket.ex


  def connect(params, socket, connect_info) do
    path = case connect_info[:uri] do
      %URI{path: p} -> p
      _ -> "unknown"
    end
    
    IO.puts("GraphqlSocket params #{inspect(params)}")
    IO.puts("GraphqlSocket socket #{inspect(socket)}")
    IO.puts("GraphqlSocket connected path: #{path}")

    {:ok, socket}
  end

Modification in endpoint.ex

  socket "/ws/gql", MySubscriptionAppSqliteWeb.GraphqlSocket, websocket: [connect_info: [:uri]], longpoll: false

:Playground

Log output on server with web playground

GraphqlSocket params %{"vsn" => "2.0.0"}
GraphqlSocket socket %Phoenix.Socket{assigns: %{}, channel: nil, channel_pid: nil, endpoint: MySubscriptionAppSqliteWeb.Endpoint, handler: MySubscriptionAppSqliteWeb.GraphqlSocket, id: nil, joined: false, join_ref: nil, private: %{}, pubsub_server: MySubscriptionAppSqlite.PubSub, ref: nil, serializer: Phoenix.Socket.V2.JSONSerializer, topic: nil, transport: :websocket, transport_pid: nil}
GraphqlSocket connected path: /ws/gql/websocket
[info] CONNECTED TO MySubscriptionAppSqliteWeb.GraphqlSocket in 5ms
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"vsn" => "2.0.0"}
[info] JOINED __absinthe__:control in 58µs
  Parameters: %{}
[debug] ABSINTHE schema=MySubscriptionAppSqliteWeb.GraphqlSchema variables=%{}
---

// ---> THIS IS NOT LOGGED ON ALTAIR:

subscription PostCreated {
  postChanged {
    created {
      id
        text
      text
    }
  }
}
---
[debug] -- Absinthe Phoenix Reply --
{:ok, %{subscriptionId: "__absinthe__:doc:NDBuu9SaWIecvz5i9JO1q8t8pVxZNpzmkO5ZKzdfHxw=:A604DB20983D4EF98C369B525464A8023C4EB34291F6CDAC41CB20E481D3B2B6"}}
----------------------------

Altair


On Altair there is no log of the subscription on the server.

GraphqlSocket params %{"vsn" => "2.0.0"}
GraphqlSocket socket %Phoenix.Socket{assigns: %{}, channel: nil, channel_pid: nil, endpoint: MySubscriptionAppSqliteWeb.Endpoint, handler: MySubscriptionAppSqliteWeb.GraphqlSocket, id: nil, joined: false, join_ref: nil, private: %{}, pubsub_server: MySubscriptionAppSqlite.PubSub, ref: nil, serializer: Phoenix.Socket.V2.JSONSerializer, topic: nil, transport: :websocket, transport_pid: nil}
GraphqlSocket connected path: /ws/gql/websocket
[info] CONNECTED TO MySubscriptionAppSqliteWeb.GraphqlSocket in 1ms
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"vsn" => "2.0.0"}

// ---> Here no log anymore. It just reconnects again and agian