apollographql / apollo-server

🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
https://www.apollographql.com/docs/apollo-server/
MIT License
13.79k stars 2.03k forks source link

Unable to start subscription server with graphql-ws protocol #7924

Open Mr-Goldberg opened 2 months ago

Mr-Goldberg commented 2 months ago

Issue Description

Hi, everyone!

I was following your guide to build server that supports subscriptions. The guide clearly says that server protocol will be graphql-ws. But I've found that the server protocol is graphql-transport-ws somehow.

I was struggling with this error on iOS side while trying to use subscription: WebSocketError(payload: nil, error: Optional(ApolloWebSocket.WebSocket.WSError(type: ApolloWebSocket.WebSocket.WSError.ErrorType.protocolError, message: "Subprotocol not acceptable", code: 4406)), kind: ApolloWebSocket.WebSocketError.ErrorKind.networkError)

Then I've added logs to the socket-server, and got a log output every second (3 outputs included):

httpServer.on("upgrade", (request, socket, head) => {
 log("upgrade", `${process.uptime()}`);
});
wsServer.on("headers", (headers, request) => {
 log("headers", `${process.uptime()} ${request.url} ${headers}`);
});
wsServer.on("connection", (socket) => {
  log("connection", `${process.uptime()} ${socket.protocol}`);
});

/*
Server log outputs:

headers 725.661031564 /graphql-subscriptions HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: tcCOpw8jUeBCdBQ75HQ+wMGIaZM=
connection 725.661696195 
upgrade 725.661997484

headers 726.716486181 /graphql-subscriptions HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: S+RHY3SevLMmJTL4RqNG+Z9kZDU=
connection 726.716700488 
upgrade 726.716893474

headers 727.787623637 /graphql-subscriptions HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: nERyI3oVrUocy4fhOuXRxZXcB8Q=
connection 727.787844604 
upgrade 727.788041241
*/

Accidentally I've switched the protocol in iOS to .graphql_transport_ws and IT WORKED! Also, there was only the single output from socket logs (which included the protocol name):

headers 748.008532921 /graphql-subscriptions HTTP/1.1 101 Switching Protocols,Upgrade: websocket,Connection: Upgrade,Sec-WebSocket-Accept: vUamFHP1yb9kEcnbWzNk9uTAXdQ=,Sec-WebSocket-Protocol: graphql-transport-ws
connection 748.008724487 graphql-transport-ws
upgrade 748.00883525

So, the question is: Am I doing something wrong (probably server-side), or is there an issue with the Server code, which somehow uses the old .graphql_transport_ws protocol?

Here is the minimal Server code: Sandbox

I was not assembling an iOS example, as there may have been an obvious error in my server code. But here's how I am assembling the Apollo client:

let graphQlEndpoint = URL(string: "https://9xd9fj-4000.csb.app/graphql")!
let graphQlWsEndpoint = URL(string: "wss://9xd9fj-4000.csb.app/graphql-subscriptions")!

let client = URLSessionClient()
let cache = InMemoryNormalizedCache()
let store = ApolloStore(cache: cache)
let provider = DefaultInterceptorProvider(client: client, store: store)
let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: graphQlEndpoint)
let webSocket = WebSocket(url: graphQlWsEndpoint, protocol: .graphql_ws)

let webSocketTransport = WebSocketTransport(websocket: webSocket)

let splitTransport = SplitNetworkTransport(
    uploadingNetworkTransport: transport,
    webSocketNetworkTransport: webSocketTransport
)

return ApolloClient(networkTransport: splitTransport, store: store)

Link to Reproduction

Sandbox

Reproduction Steps

Set up the Apollo server by this guide and try to use a subscription.

Expected result: Subscription is working with the graphql-ws protocol

Actual result:

Mr-Goldberg commented 2 months ago

Well, ok, I found the issue 😅

I've mistakenly used .graphql_ws instead of .graphql_transport_ws in the iOS client. However, this is a counterintuitive option, as the correct options for the Apollo Server and Apollo Studio Explorer are graphql-ws, but for iOS, it is vice versa.

Screenshot 2024-08-26 at 21 08 43

It would be great if you could address this issue - maybe by providing:

  1. Clearer sub-protocol option for iOS client
  2. Clearer error message for iOS client
  3. Error message for the server about an attempt to connect with the wrong sub-protocol

Also, I want to thank the team - this is a great product! It was easy to set up and a pleasure to use! Before this issue 😅