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

Apollo v3 React Native errors handling doesn't work #7750

Closed
FRizzonelli opened this issue Feb 23, 2021 · 3 comments
Closed

Apollo v3 React Native errors handling doesn't work #7750

FRizzonelli opened this issue Feb 23, 2021 · 3 comments

Comments

@FRizzonelli
Copy link

FRizzonelli commented Feb 23, 2021

Intended outcome:

Error handling of graphQL errors should be possibile at component level

Actual outcome:

Tracking graphQL errors at component level is always undefined.

How to reproduce the issue:

I'm trying to handle graphQLErrors inside my react native components, but I think there is some issues with the error propagation. I've configured my client as follow:

const httpLink = createHttpLink({ uri: API_SERVER_URL });

const authLink = setContext(async (_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = await SecureStorage.getItem(StorageKeys.AUTH_TOKEN);
  // return the headers to the context so httpLink can read them
  console.log('auth token injected', token);

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

const errorLink = onError(({ graphQLErrors, networkError, forward, operation, response }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, locations, path }) => {
      console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
      store.dispatch(
        showToast({
          type: ToastType.ERROR,
          message
        })
      );
    });
  }
  if (networkError) {
    console.log(`[Network error]: ${networkError}`);
  }
});

const client = new ApolloClient({
  link: errorLink.concat(authLink.concat(httpLink)),
  cache: new InMemoryCache(),
  assumeImmutableResults: true,
  queryDeduplication: true,
  defaultOptions: {
    watchQuery: {
      fetchPolicy: 'cache-and-network',
      errorPolicy: 'none'
    },
    query: {
      fetchPolicy: 'cache-first',
      errorPolicy: 'all'
    }
  }
});

GraphQLErrors inside my error link is working perfectly, I can see the errors and showing my toast with redux smoothly. Problem is that at component level, error is always broken. I've tried all possibile configuration for firing my calls with following methods:

useQuery hook

const { loading, error, data } = useQuery(MY_QUERY);

useApolloClient hook and manually firing the query

client
  .query<MeTypes.MeQuery, MeTypes.MeVariables>({
    query: ME
  })
  .then(r => {
    console.log(r);
  })
  .catch(error => {
    console.log(error);
  });

useMutation hook

const [fetchMutation, { loading, error, data }] = useMutation(MY_MUTATION);

In every situation, error property always contains only the network error (as raised exception). I'd expect to have and error object with all the properties (i.e. .graphQLErrors and .networkError), instead inside error I have the actual ApolloException.

This is my debug console, as you can see the first two logs are from errorLink interceptor and they works

[GraphQL error]: Message: You need to be logged to access this field, Location: [object Object], Path: me
App.tsx:60 
[Network error]: ServerError: Response not successful: Received status code 401

The last one if from my component and I'm printing error object. I'd except to see an object, instead it seems that the error isn't properly handled inside apollo.

MyComponent.tsx:55 Error: Response not successful: Received status code 401
    at new ApolloError (errors.cjs.js:31)
    at core.cjs.js:1485
    at utilities.cjs.js:958
    at tryCallTwo (core.js:45)
    at doResolve (core.js:200)
    at new Promise (core.js:66)
    at Object.error (utilities.cjs.js:958)
    at notifySubscription (Observable.js:140)
    at onNotify (Observable.js:179)
    at SubscriptionObserver.error (Observable.js:240)

If I print the destructured error, graphQLErrors is an empty array

I've tried to change all the possible error policies, nothing changes :( Also tried different versions of apollo client but no luck.

Issues that I've already checked for solution:
#6520
#5708

EDIT:
I've found this issue apollographql/apollo-link#1022 which seems related. If server throws a 400 Bad Request with also graphQLErrors, I'd be able to manage them properly.
Also here apollographql/apollo-link#855 it's mentioned the same problem.

How is it possible to achieve this?

Versions

System:
OS: macOS 10.15.6
Binaries:
Node: 14.8.0 - /usr/local/bin/node
Yarn: 1.22.10 - ~/Code/switcho/node_modules/.bin/yarn
npm: 6.14.7 - /usr/local/bin/npm
Browsers:
Chrome: 88.0.4324.182
Firefox: 67.0
Safari: 13.1.2
npmPackages:
@apollo/client: 3.4.0-beta.1 => 3.4.0-beta.1
apollo: ^2.32.1 => 2.32.1

@FRizzonelli
Copy link
Author

After further investigation, I was able to use this interceptor to properly propagate errors in our chain

const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    graphQLErrors.forEach(({ message, locations, path }) => {
      console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
      // show some popup or any global related handling to your errors
    });
  }
  if (networkError) {
    console.log(`[Network error]: ${networkError}`);

    return new Observable(obs => {
      obs.error(
        new ApolloError({
          errorMessage: networkError.message,
          graphQLErrors,
          networkError
        })
      );
    });
  }
});

This way, if my backend response status code is different from 200 and we have some graphQLError, we can manage them from components.
I still think this is an issue but at least I hope the workaround can help someone!

@jcreighton
Copy link
Contributor

@FRizzonelli Think you could get a small, runnable reproduction working with Snack? I know it's harder to create reproduction for React Native so maybe this could help.

@hwillson
Copy link
Member

If someone can provide a small runnable reproduction that demonstrates this happening with @apollo/client@latest, we'll take a closer look. Thanks!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants