Search code examples
angularangular-materialgraphqlapollo

showing MatSnackBar message when Apollo GraphQL fails with an error


I have a website that uses Angular 10 and Apollo GraphQL.

Whenever a request fails I want to show an error to the user uses MatSnackBar, but I don't know how to provide the MatSnackBar component to the OnError() function of the apollo-link-error.

This is my graphql.module.ts code:

import {NgModule} from '@angular/core';
import {APOLLO_OPTIONS} from 'apollo-angular';
import {ApolloClientOptions, ApolloLink, InMemoryCache} from '@apollo/client/core';
import {HttpLink} from 'apollo-angular/http';
import { onError } from 'apollo-link-error';

function getNewToken(): any {
  //TODO: need to implement
}

const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => {
    if (graphQLErrors) {
      for (const err of graphQLErrors) {
        switch (err.extensions?.code) {
          case 'UNAUTHENTICATED':
            // error code is set to UNAUTHENTICATED
            // when AuthenticationError thrown in resolver

            // modify the operation context with a new token
            const oldHeaders = operation.getContext().headers;
            operation.setContext({
              headers: {
                ...oldHeaders,
                authorization: getNewToken(),
              },
            });
            // retry the request, returning the new observable
            return forward(operation);
        }
      }
      graphQLErrors.map(({ message, locations, path }) =>
        console.log(
          `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
        ),
      );
    }

    if (networkError) {
      console.log(`[Network error]: ${networkError}`);
      // if you would also like to retry automatically on
      // network errors, we recommend that you use
      // apollo-link-retry
    }
  }
);

const uri = 'http://localhost:8081/graphql';
export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {
  const httpLinkHandler = httpLink.create({uri});
  const httpLinkWithErrorHandling = ApolloLink.from([
    // @ts-ignore
    errorLink,
    httpLinkHandler,
  ]);

  return {
    link: httpLinkWithErrorHandling,
    cache: new InMemoryCache(),
  };
}

@NgModule({
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink],
    },
  ],
})
export class GraphQLModule {}

Where do I display the errors using console.info? I want to show a snack bar instead. Any ideas?


Solution

  • I found the solution soon after I created the bounty. so it's only a matter of injecting the MatSnackbar, copying it to a local variable to be used in the error object.

    So in the providers dependencies I added the MatSnackBar to the dependencies:

    @NgModule({
      providers: [
        {
          provide: APOLLO_OPTIONS,
          useFactory: createApollo,
          deps: [HttpLink, MatSnackBar],
        },
      ],
    })
    export class GraphQLModule {}
    

    then in the createApollo() function I copied the matSnackBar to a local variable:

    export function createApollo(httpLink: HttpLink, matSnackBar: MatSnackBar): ApolloClientOptions<any> {
          localMatSnackbar = matSnackBar;
    

    then in the onError() handler I used it on network error:

    if (networkError) {
      localMatSnackbar?.open(networkError.message, 'DISMISS', {
        duration: 2000,
        verticalPosition: 'top'
      });
    

    and that's it!

    If there is a more elegant way to resolve it, I'll be more than happy to accept a different answer.