Apollo Client useSubscription not reading correct link

I hope you are doing well!

We are trying to implement web sockets in our website and we are using Apollo/Client v3 for the client side. Everything is working perfectly except for the subscription.

Here is the code for my client:

import { ApolloClient, InMemoryCache, split } from "@apollo/client";
import { getMainDefinition } from "@apollo/client/utilities";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
import { HttpLink } from "apollo-link-http";

import { link, socketLink } from "./gql-link";

const httpLink = new HttpLink({
  uri: link,
});

const wsLink = new GraphQLWsLink(
  createClient({
    uri: socketLink,
  })
);

const splitLink = split(
  ({ query }) => {
    const { kind, operation } = getMainDefinition(query);
    return kind === "OperationDefinition" && operation === "subscription";
  },
  wsLink,
  httpLink
);

const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});

export default client;

the url used are:

export const link="http://dummydomain/backend/graphql/graphql";
export const socketLink = "ws://dummydomain/backend/graphql/graphql"

and here is the code for my subscription:


  const { subData } = useSubscription(
    ON_UPDATE_STATIONS,
    {
      variables: {
        req: {
          enableFilters: true,
          filters: filtersState,
          keys: {
            page: page + 1,
            pageSize: rowsPerPage,
          },
          siteID: fromSites ? siteGuid : null,
          keyword: search,
          orderColumn: orderColumn,
          orderDirection: orderDirection,
          //noSitesStations: false,
          userID: storeUserGuid,
        },
      }
    }
  );

and here is my subscription:

export const ON_UPDATE_STATIONS = gql`
  subscription ($req: GetStationsListModelInput!) {
    onUpdateStationSubscription(model: $req) {
      stationsListModel {
        stations {
          stationGuid
          stationStatus {
            description
          }
        }
        totalNumberOfRecords
      }
      errorMessage
      errorCode
    }
  }
`;

Whenever I open the page the subscription is on, I get the following error in the console

POST http://dummydomain/backend/graphql/graphql 500 (Internal Server Error)

I tried using the subscribeToMore property this way instead of the useSubscription

    subscribeToMore({
    document: ON_UPDATE_STATIONS,
    updateQuery: (prev, { subscriptionData }) => {
     console.log(prev, subscriptionData)
    }
  });

and I got an additional error in the console

Unhandled GraphQL subscription error ServerError: Response not successful: Received status code 500

We are using the same links for web (React) and mobile (Flutter), and with flutter, the websocket is working so I don’t think is it because of the server. What could be the problem? I followed the entire Apollo/Client documentation on useSubscription.

Hey @Selimm12 :wave:

It’s a bit difficult to understand with the code given here what exactly is happening without being able to interact with the code. Have you logged inside your split function to make sure it’s returning true when trying to send the subscription? The only reason the httpLink should be used is when that value is false, so let’s make sure to rule that possibility out.

Helloo @jerelmiller ,

When I console log inside the split function

const splitLink = split(
  ({ query }) => {
    const { kind, operation } = getMainDefinition(query);

    console.log({query, kind, operation })
    return kind === "OperationDefinition" && operation === "subscription";
  },
  wsLink,
  httpLink
);

I am getting only the first value ever and it’s never being called again, no matter if the url changes in React, unless I refresh the page then I get the result of the first query I have in the page then nothing is displayed again no matter any other page I enter unless I refresh.

no matter if the url changes in React

I’m not entirely sure what you mean here. Based on your code samples, it looks like you have static URLs. Would you be willing to share more on how you’re managing the URL?

It would make sense that you’d only ever see the split function called once if you’re issuing a single useSubscription, but I’m not sure what other queries/operations you’re sending through. What is logged in the invocation of that function?

Due to some protocols I am unable to share the exact URLs, however both urls

export const link="http://dummydomain/backend/graphql/graphql";
export const socketLink = "ws://dummydomain/backend/graphql/graphql"

are found in a separate file in my code and I’m importing them inside the file where I’m defining the client.

As for the single call, I do have only 1 useSubscription, but I have 3 other useQueries in the same page, and since queries execute before subscriptions, it is taking the first query in the page and then it stops, neither does it take the 2 other queries, nor the subscription, nor the LazyQuery.

What I get in the console when I console log console.log({ kind, operation }) is {kind: 'OperationDefinition', operation: 'query' } since it’s only reading the first query run on the page. Even if I route to a different page it is not taking any queries or subscriptions or lazyqueries on that other page unless I refresh the browser entirely.

That is very odd. I can’t say I’ve ever seen this happen.

Since this is difficult to reproduce, it would be super helpful if you can provide a reproduction. You can use our error template which includes a subscription as well. Try and replicate your code as much as possible as there could be a clue in there. Hopefully you’re able to find a way to show the bug. Thanks!

I found the problem, it was because at some point in my code, I was emptying the client and then refilling it, but I didn’t take into consideration that I had to refill it with the web socket link as well.

Thank you very much for your time!

Awesome! Glad to hear you found the source of the issue!