Hendry Lim
Hendry Lim

Reputation: 1974

Apollo Subscriptions not listening to new data on client

Previously my apollo setup was listening to subscriptions until I added in socket.io and now my client setup is no longer listening to new data. my server codes seem to be ok based on my testing using graphql playground.

in my browser console, i get the following error message

client.js:652 WebSocket connection to 'ws://localhost:4000/' failed: Error during WebSocket handshake: Unexpected response code: 400

There seems to be some issue with my client side setup to use apollo subscriptions.

Appreciate any pointers? Thanks in advance

import { ApolloClient } from "apollo-client";
import { onError } from "apollo-link-error";
import { ApolloLink, split } from "apollo-link";
import { createUploadLink } from "apollo-upload-client";
import gql from "graphql-tag";
import { withClientState } from "apollo-link-state";
import { InMemoryCache } from "apollo-cache-inmemory";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";
import { setContext } from "apollo-link-context";

    const cache = new InMemoryCache();

    const defaultState = {
      currentGame: {
        __typename: "currentGame",
        teamAScore: 0,
        teamBScore: 0,
        teamAName: "EAGLES",
        teamBName: "LOL"
      }
    };

    const stateLink = withClientState({
      cache,
      defaults: defaultState,
      resolvers: {
        Mutation: {
          updateGame: (_, { index, value }, { cache }) => {
            const query = gql`
              query GetCurrentGame {
                currentGame @client {
                  teamAScore
                  teamBScore
                  teamAName
                  teamBName
                }
              }
            `;
            const previous = cache.readQuery({ query });
            const data = {
              currentGame: {
                ...previous.currentGame,
                [index]: value
              }
            };
            cache.writeQuery({ query, data });
            return null;
          },
          resetCurrentGame: (_, d, { cache }) => {
            cache.writeData({ data: defaultState });
          }
        }
      }
    });

    const host = "http://localhost:4000";

    // httpLink
    const httpLink = createUploadLink({
      uri: `${host}/graphql`,
      credentials: "same-origin"
    });

    // wsLink
    const wsLink = new WebSocketLink({
      uri: `ws://localhost:4000/`,
      options: {
        reconnect: true
      }
    });

    // using the ability to split links, you can send data to each link
    // depending on what kind of operation is being sent
    const webLink = split(
      // split based on operation type
      ({ query }) => {
        const { kind, operation } = getMainDefinition(query);
        return kind === "OperationDefinition" && operation === "subscription";
      },
      wsLink,
      httpLink
    );

    // authMiddleware
    const authLink = setContext(async (req, { headers }) => {
      //  const token = await AsyncStorage.getItem("@token");
      const token = "";

      return {
        headers: {
          ...headers,
          authorization: token ? `${token}` : ""
        }
      };
    });

    const errorLink = onError(({ networkError, graphQLErrors }) => {
      if (graphQLErrors) {
        graphQLErrors.map(({ message, locations, path }) =>
          console.log(
            `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
          )
        );
      }
      if (networkError) console.log(`[Network error]: ${networkError}`);
    });

    export const client = new ApolloClient({
      link: ApolloLink.from([authLink, stateLink, errorLink, webLink]),
      cache
    });

My server side code if required

//! Using Apollo Server Express
const app = express();
const path = "/graphql";
const schema = genSchema();

export const startServer = async () => {
  const server = new ApolloServer({
    schema,
    context: ({ req }: any) => ({
      req,
      pubsub,
      userLoader: userLoader()
    })
  });

  app.use(cors());

  app.use(authMiddleware);

  app.use("/images", express.static("images"));

  app.use(
    "graphql",
    graphqlUploadExpress({
      uploadDir: "/",
      maxFileSize: 100000000,
      maxFiles: 10
    }),
    graphqlHTTP({ schema }) as any
  );

  server.applyMiddleware({ app, path });

  //! Added Subscription Handler
  const httpServer = createServer(app);
  server.installSubscriptionHandlers(httpServer);

  const port = process.env.PORT || 4000;

  await createConnection();

  await httpServer.listen({
    port
  });

  console.log(`Server is running on localhost:${port}${server.graphqlPath}`);
};

Upvotes: 2

Views: 2527

Answers (1)

Hendry Lim
Hendry Lim

Reputation: 1974

Rectified. My client side apollo setup should point to ws://localhost:4000/graphql and not just ws://localhost:4000/

// wsLink
const wsLink = new WebSocketLink({
  uri: `ws://localhost:4000/graphql`,
  options: {
    reconnect: true
  }
});

Upvotes: 2

Related Questions