apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.34k stars 2.66k forks source link

WebSocket connection to 'ws://localhost:4000/graphql' failed: #11917

Closed asadDev02 closed 3 months ago

asadDev02 commented 3 months ago
import { PropsWithChildren, useMemo } from 'react';
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider as ApolloClientProvider,
  split,
  HttpLink,
  ApolloLink,
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { onError } from '@apollo/client/link/error';
import { useAuthStore, useConfigStore } from 'store';
import { useAlert } from 'hooks/useAlert';
import { fetchAuthSession } from 'aws-amplify/auth';
import { GraphQLWsLink } from "@apollo/client/link/subscriptions"
import { createClient } from 'graphql-ws';
import { getMainDefinition } from "@apollo/client/utilities"

export const ApolloProvider = ({ children }: PropsWithChildren) => {
  const { authToken, setAuthToken, onLogout, setAuthTokenExpiry } = useAuthStore();

  const isProduction = import.meta.env.MODE === 'production';

  const { config } = useConfigStore()

  const httpLink = new HttpLink({
    uri: `https://${config?.envDomainName}/graphql`,
  });

  const wsLink = new GraphQLWsLink(createClient({
    url: `ws://${config?.envDomainName}/graphql`,
  }));

  const { onAlertTrigger } = useAlert();

  const authLink = setContext((_, { headers }) => {
    return {
      headers: {
        ...headers,
        Authorization: authToken ? `Bearer ${authToken}` : '',
      },
    };
  });

  const errorLink = onError(({ networkError }) => {
    if (networkError) {
      const netWorkError = networkError as any;

      const isUnAuthorized =
        netWorkError?.response?.statusText?.includes('Unauthorized') ||
        netWorkError?.response?.status === 401;

      if (isUnAuthorized) {
        (async () => {
          let authToken = await fetchAuthSession();

          const token = authToken?.tokens?.accessToken?.toString();

          const tokenExpiry = authToken?.credentials?.expiration?.toString();

          if (tokenExpiry) {
            setAuthTokenExpiry(tokenExpiry);
          }
          if (token) {
            setAuthToken(token);
          } else {
            onAlertTrigger({
              type: 'error',
              message: 'Your session has expired. Please login again.',
            });

            setTimeout(() => {
              onLogout();
            }, 1000);
          }
        })();
      }
    }
  });

  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === 'OperationDefinition' &&
        definition.operation === 'subscription'
      );
    },
    wsLink,
    errorLink.concat(authLink).concat(httpLink),
  );

  const apolloClient = useMemo(
    () =>
      new ApolloClient({
        link: splitLink,
        cache: new InMemoryCache(),
        connectToDevTools: !isProduction,
      }),
    [authToken],
  );

  return <ApolloClientProvider client={apolloClient}>{children}</ApolloClientProvider>;
};
import CacheBuster from 'react-cache-buster';
import {
  ApolloProvider,
  ConfigProvider
} from 'providers';
import { Routes } from 'core/Routes';
import AuthLoader from 'components/AuthLoader';
import { version } from '../../../package.json';

const isProduction = import.meta.env.MODE === 'production';

export const app = () => {

  return (
    <CacheBuster
      currentVersion={version}
      isEnabled={isProduction}
      isVerboseMode={false}
      loadingComponent={<AuthLoader />}
      metaFileDirectory={'.'}
    >
      <ConfigProvider>
        <ApolloProvider>

          <Routes />
        </ApolloProvider>
      </ConfigProvider>
    </CacheBuster>
  );
};

export default app;
import { gql, useSubscription } from '@apollo/client';

const COMMENTS_SUBSCRIPTION = gql`
  subscription IntentionPrioritized($userId: UUID!) {
  intentionPrioritized(userId: $userId) {
    id
  }
}
`;

export const index = () => {

  const { data, loading } = useSubscription(
    COMMENTS_SUBSCRIPTION,
    { variables: { userId: "beb18a38-7d1d-46c6-b455-6f94f986bd53" } }
  );
  console.log("data: ",data);
  return <h4>New comment: test</h4>;
}

getting this issue

WebSocket connection to ‘ws://localhost:4000/graphql’ failed: (anonymous) @ graphql-ws.js?v=0002dea8:332 Show 1 more frame Show lessUnderstand this error index.tsx:30 data: undefined

jerelmiller commented 3 months ago

Hey @Muhammad-Asad-Mughal 👋

Unfortunately its very difficult to understand what the issue is without a runnable reproduction or access to your server.

GraphQLWsLink is just a small wrapper around the graphql-ws client to be able to subscribe and send updates back through the link chain, but it doesn't do any of the network stuff itself. For that, you'll need to debug why your graphql-ws client isn't able to connect.

A couple things to check on your end:

Since this isn't an issue with Apollo Client, I'm going to go ahead and close this issue. Hopefully you're able to figure out why your websocket endpoint won't connect. Please let me know if I've made a mistake and I'd be happen to open this again. Thanks!

github-actions[bot] commented 3 months ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

github-actions[bot] commented 2 months ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. For general questions, we recommend using StackOverflow or our discord server.