Gracefully Handle Apollo Angular Error Using RxJS

Shihao Xia
2 min readOct 28, 2018

--

RxJS is a really awesome tool to handle data stream.

Image Source: https://malcoded.com

After we fired a query, actually we only care about two things:

  1. waiting time (probably need to show some loading spinner or bar)
  2. result (either error or response we expect)

The idea behind this is just let user know what is going on here, either in waiting or result.

Thankfully apollo provides excellent method to handle these two things: RxJS.

Let’s first look at one example, just simply query & show data:

@Component(...)
class ExampleComponent implements OnInit {
data: Observable<any>;
isLoading = false;
constructor(private apollo: Apollo){}

ngOnInit(): void {
this.fetch();
}

fetch():void {
this.data = this.apollo
.query({query:YourQuery})
.pipe(
// you can also merge loading assignment into map tap(result => this.isLoading = result.loading),
filter(result => !result.loading)
map(result => (<any>result.data).whateveryourwhattoshow)
)
}
}

Then we can just use async pipe in Angular to show the data.

<div *ngIf="!isLoading">{{ data | async }}</div>
<div *ngIf="isLoading">Loading...</div>

What if there some errors happened here? Maybe is dns timeout, is authentication problem?

Apollo groups these errors in to ApolloError, which has two fields: graphQLErrors and networkError. One thing is graphQLErrors is an array however networkError is not. Each of them has a field call message, which is basically you want to show to the users.

RxJS provides an excellent operator call catchError to capture the error

.pipe(
// you can also merge loading assignment into map
tap(result => this.isLoading = result.loading),
filter(result => !result.loading),
map(result => (<any>result.data).whateveryourwhattoshow),
catchError(err => {
// whatever you want to handle error
if (err.graphQLErrors) {
err.graphQLErrors.forEach(e => {...});
}
if (err.networkError) { ... }
// default return
return of([]);
})
)

Now, any error occurred has been perfectly handled by you :)

What if I want to subscribe the data (not only just show data using async pipe ) ?

Simple, just move your error handler to subscribe. subscribe second parameter is error callback.

this.apollo.query(...)
.pipe(...)
.subscribe(
data => {},
err => {}
)

What if I want to integrate error with message service (such as MatSnackBar or your custom service to show error message) ?

Also simple, just wrapper error handler with a high level function which returns a error handler

function handleApolloGraphQLError(  
yourcustomservice: any,
unknownErrorMessage: string = '',
customHandler?: () => void) {
// you can add any dependency in the params
return (err: ApolloError) => {
// yourcustomservice.show(err)
};
}

Welcome to leave your any thoughts :)

--

--