Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The WS connection failed, I'm not sure where the configuration issue is #338

Closed
wuzikai18 opened this issue Aug 1, 2024 · 7 comments
Closed

Comments

@wuzikai18
Copy link

wuzikai18 commented Aug 1, 2024

image

ApolloWrapper.tsx
"use client"
import { HttpLink, split } from "@apollo/client"
import { GraphQLWsLink } from "@apollo/client/link/subscriptions"
import { getMainDefinition } from "@apollo/client/utilities"
import { ApolloClient, ApolloNextAppProvider, InMemoryCache } from "@apollo/experimental-nextjs-app-support"
import { createClient } from "graphql-ws"

// Helper function to create a client
function makeClient() {
  const httpLink = new HttpLink({
    uri: "https://zion-app.functorz.com/zero/y7xXo5wAY9o/api/graphql-v2",
    fetchOptions: { cache: "no-store" },
    headers: {
      Authorization:
        "xxx",
    },
  })

  const wsClient = createClient({
    url: "wss://zion-app.functorz.com/zero/y7xXo5wAY9o/api/graphql-subscription",
    connectionParams: {
      Authorization:
        "xxx",
    },
    on: {
      connected: () => console.log("WebSocket connected"),
      closed: (event) => console.log("WebSocket closed", event),
      error: (error) => console.log("WebSocket error", error),
    },
  })

  const wsLink = new GraphQLWsLink(wsClient)

  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query)
      return definition.kind === "OperationDefinition" && definition.operation === "subscription"
    },
    //@ts-ignore
    wsLink,
    httpLink
  )

  return new ApolloClient({
    ssrMode: true,
    cache: new InMemoryCache(),
    link: splitLink,
  })
}

// Component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
  return <ApolloNextAppProvider makeClient={makeClient}>{children}</ApolloNextAppProvider>
}

'use client';
import { gql, useSubscription } from '@apollo/client';

const MESSAGE_ADDED_SUBSCRIPTION = gql`
  subscription get_messages {
    message {
      id
      created_at
      updated_at
      content
      deleted
    }
  }
`;
const { data, loading, error } = useSubscription(MESSAGE_ADDED_SUBSCRIPTION, {
    skip: typeof window == "undefined",
  });
@phryneas
Copy link
Member

phryneas commented Aug 5, 2024

You seem to be getting a WebSocket error, but at first look that doesn't seem to be related to Apollo Client. Can you try to remove AC from the picture and report back if it works opening a direct WebSocket connection without Apollo Client?

@Sudhanshu8257
Copy link

is there a demo for setting up client with
wss connection

the example provided doesn't that muxh
unable to setup in my next 14 app

@phryneas
Copy link
Member

@Sudhanshu8257 There is nothing different compared to Apollo Client outside of Next.js, you should be able to go with the normal examples.

@geoffraymond
Copy link

@wuzikai18 @Sudhanshu8257 did either of you ever figure this out?

@phryneas could you provide a working example?

@geoffraymond
Copy link

geoffraymond commented Dec 26, 2024

I got this working with the following code:

ApolloWrapper.tsx

'use client';

import { HttpLink, split } from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import {
  ApolloClient,
  ApolloNextAppProvider,
  InMemoryCache,
} from '@apollo/experimental-nextjs-app-support';
import { WebSocketLink } from '@apollo/client/link/ws';

const GRAPHQL_ENDPOINT = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || '';
const GRAPHQL_WS_ENDPOINT = process.env.NEXT_PUBLIC_GRAPHQL_WS_ENDPOINT || '';

export const ApolloWrapper = ({ token, children }) => {
  // Create an HttpLink
  const httpLink = new HttpLink({
    uri: GRAPHQL_ENDPOINT,
    headers: {
      authorization: `Bearer ${token}`,
    },
  });

  // Create a WebSocket link
  const wsLink = new WebSocketLink({
    uri: GRAPHQL_WS_ENDPOINT,
    options: {
      reconnect: true,
      connectionParams: {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      },
    },
  });

  // Use split to route queries and subscriptions
  const link = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
    },
    wsLink,
    httpLink
  );

  /**
   * Create a new Apollo Client instance with the appropriate link.
   *
   * The link is split to use a WebSocket link for subscriptions and an HTTP link for queries and mutations.
   * The WebSocket link is configured to reconnect in case of an error and  to use the provided token in the Authorization header..
   * The HTTP link is configured to use the provided token in the Authorization header.
   *
   * @returns {ApolloClient<NormalizedCacheObject>} A new Apollo Client instance.
   */
  const makeClient = () => {
    return new ApolloClient({
      cache: new InMemoryCache(),
      link,
    });
  };

  return <ApolloNextAppProvider makeClient={makeClient}>{children}</ApolloNextAppProvider>;
};

I get the JWT token from Auth0 then pass the token in from the layout file to the wrapper.

layout.tsx

import '@mantine/core/styles.css';

import { getAccessToken } from '@auth0/nextjs-auth0';

import { UserProvider as AuthUserProvider } from '@auth0/nextjs-auth0/client';
import { MantineProvider, ColorSchemeScript } from '@mantine/core';
import { GeistSans } from 'geist/font/sans';
import { GeistMono } from 'geist/font/mono';

import { theme } from '../theme';
import { ApolloWrapper } from './ApolloWrapper';
import { Shell } from '@/components/AppShell';
import AppUserProvider from './AppUserProvider';
import PNGFavicon from '@/public/favicon.png';
import SVGFavicon from '@/public/favicon.svg';
import FrontChat from '@/components/FrontChat';
import SegmentAnalytics from '@/lib/segment-analytics';
import './output.css';

export const metadata = {
  title: 'TITLE HERE',
  icons: {
    icon: [
      {
        rel: 'icon',
        type: 'image/png',
        url: PNGFavicon.src,
        href: PNGFavicon.src,
      },
      {
        rel: 'icon',
        type: 'image/svg+xml',
        url: SVGFavicon.src,
        href: SVGFavicon.src,
      },
    ],
  },
};

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const { accessToken } = await getAccessToken();

  return (
    <html lang="en" className={(GeistSans.className, GeistMono.className)}>
      <head>
        <ColorSchemeScript />
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
        />
        {SegmentAnalytics.getHeader()}
      </head>
      <AuthUserProvider>
        <body>
          <ApolloWrapper token={accessToken}>
            <AppUserProvider>
              <MantineProvider defaultColorScheme="light" theme={theme}>
                <Shell>{children}</Shell>
              </MantineProvider>
            </AppUserProvider>
          </ApolloWrapper>
        </body>
      </AuthUserProvider>
    </html>
  );
}

@wuzikai18
Copy link
Author

"use client"
import { HttpLink, split } from "@apollo/client"
import { WebSocketLink } from "@apollo/client/link/ws"
import { getMainDefinition } from "@apollo/client/utilities"
import { ApolloClient, ApolloNextAppProvider, InMemoryCache } from "@apollo/experimental-nextjs-app-support"

// Helper function to create a client
function makeClient() {
const httpLink = new HttpLink({
uri: "https://xxxxxx/api/graphql-v2",
fetchOptions: { cache: "no-store" },
headers: {
Authorization:
"xxx",
},
})

const wsLink = new WebSocketLink({
uri: "wss://xxxxxx/api/graphql-subscription",
options: {
reconnect: true,
connectionParams: {
Authorization: xxxx,
},
},
})

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

return new ApolloClient({
ssrMode: true,
cache: new InMemoryCache(),
link: splitLink,
})
}

// Component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
return {children}
}

This is my current configuration code. There was indeed an issue with the previous WS configuration

Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants