Here is my graphqlClient.ts file:

import {
  ApolloClient,
  HttpLink,
  ApolloLink,
  InMemoryCache,
  concat,
  Operation,
  NextLink,
  FetchResult,
  Observable,
  split,
} from '@apollo/client';
import { getMainDefinition } from '@apollo/client/utilities';
import auth, { FirebaseAuthTypes } from '@react-native-firebase/auth';
import Config from 'react-native-config';

const httpLink = new HttpLink({ uri: Config.BE_BASE_URL });

import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'ws://my-gqlserver.railway.app/graphql',
  }),
);

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

const authMiddleware = new ApolloLink(
  (operation: Operation, forward: NextLink): Observable<FetchResult> => {
    return new Observable(observer => {
      (async () => {
        const currentUser: FirebaseAuthTypes.User | null = auth().currentUser;
        const token = currentUser ? await currentUser.getIdToken(false) : null;
        operation.setContext({
          headers: {
            Authorization: token ? `Bearer ${token}` : '',
          },
        });
        return forward(operation).subscribe({
          next: observer.next.bind(observer),
          error: observer.error.bind(observer),
          complete: observer.complete.bind(observer),
        });
      })();
    });
  },
);

const graphQLClient = new ApolloClient({
  cache: new InMemoryCache(),
  link: concat(authMiddleware, splitLink),
});

export default graphQLClient;

Here is the query:

export const SUBSCRIBE_TO_LOCATIONS = gql`
  subscription Subscription {
    locations
  }
`;

And on Home screen I'using useSubscription hook from @apollo/client

HomeScreen.tsx:

import { useSubscription, useQuery } from '@apollo/client';
import { SUBSCRIBE_TO_LOCATIONS } from '../graphql/queries';

  const { data: subscriptionData, loading: subscritionLoading } =
    useSubscription(SUBSCRIBE_TO_LOCATIONS, {
      onData: subData => {
        console.log('onData', subData);
      },
    });

  console.log(subscriptionData, 'subscriptionData'); 
  //  iOS ==> undefined subscriptionData
 //   android ==> array of coordinates

I'm doing everything from the official docs, and for websocekt protocols I'm using graphql-ws because subscriptions-transport-ws is deprecated, as mentioned in docs.

I'm pretty sure everything is connected well because on android works how it should, so my guess is there is something elese I need to configure on ios but I'm not sure what.

1

There are 1 answers

0
Mordred On BEST ANSWER

Sorry this came late but i had a similar issue recently;

Change this

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'ws://my-gqlserver.railway.app/graphql',
  }),
);

to this

const wsLink = new GraphQLWsLink(
  createClient({
    url: 'wss://my-gqlserver.railway.app/graphql',
  }),
);

Basically we are changing the insecure ws:// to the secure wss:// . iOS doesn't allow loading from insecure links on either http or ws as opposed to https or wss. You could override this behaviour by editing info.plist's transport security key (or something like that) but i am guessing you are on Expo's managed workflow and it might be hard to do this except you eject or switch to the bare workflow.

Cheers.