We help IT Professionals succeed at work.

Understand TypeScript catchError in Angular

Paul Konstanski
on
I have two recommended ways of doing an Angular API call.  

Both of them work but I am trying to understand the difference.  Any insight would be appreciated...


Here is the first option.
  public get(url: string, options?: any) {
     return this.http.get(url, options);
  }

Open in new window


This is the second option.
  public get(url: string, options?: any) {
    return this.http.get(url, options)
    .pipe(map(getdata => {
      console.log("apiSvc.19 | get RETURN: ",getdata);
      return getdata;
    }),
    catchError(this.handleError('api-http-svsc.27 | API for getURL ['+url+']', options))); 
  }

Open in new window

Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2017
Distinguished Expert 2019
Commented:
The second one is an older way of doing it - before the HTTPClientModule came out - you had to catch the return and decode it yourself. Angular now does that for you.

In your example though the second method is not doing anything - you are mapping over the incoming changes and then simply returning what you get - which has no effect.

Personally I use the toPromise() call on the http service get as http requests are one time calls - they don't keep omitting. There are cases where you want to use it as an observable - I just prefer not to.
rrzstudent
CERTIFIED EXPERT
Commented:
catchError is a RxJS operator. See
https://www.learnrxjs.io/learn-rxjs/operators/error_handling/catch   
https://blog.angular-university.io/rxjs-error-handling/   
It allows us to gain more control when an error occurs.
I wrote a demonstration project.  Please look at it at  
https://stackblitz.com/edit/angular-g1ty7q 
Note that if you break the url with something like
https://jsonplaceholder.typicode.com/todozzzzzzzs/1   
then you will see
getDate failed: Http failure response for https://jsonplaceholder.typicode.com/todzzzzzzzos/1: 404 OK  
in the console. Also, the handleError method allows us to send a substitute Observable to provide default data to the template.
Here is  app.component.ts
import { Component, OnInit } from "@angular/core";
import { Observable, of } from "rxjs";
import { catchError } from "rxjs/operators";
import { HttpClient } from "@angular/common/http";
import { ServerData } from "./ServerData";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  name = "Angular";
  //url = "https://jsonplaceholder.typicode.com/todozzzzzzzs/1";
  url = "https://jsonplaceholder.typicode.com/todos/1";
  serverData: ServerData;
  constructor(private http: HttpClient) {}
  ngOnInit() {
    this.getDate().subscribe(data => {
      this.serverData = data;
    });
  }
  getDate(): Observable<ServerData> {
    return this.http.get<ServerData>(this.url).pipe(
      catchError(
        this.handleError("getDate", {
          userId: 0,
          id: 0,
          title: "error occurred",
          completed: false
        })
      )
    );
  }
  private handleError<T>(operation, result?: T) {
    return (error: any): Observable<T> => {
      //console.error(error);
      console.log(`${operation} failed: ${error.message}`);
      return of(result as T);
    };
  }
}

Open in new window

 here is  app.component.html
<hello name="{{ name }}"></hello>
<p *ngIf="serverData else loading">
  userId is {{serverData.userId}}<br>
  id is {{serverData.id}}<br>
  title is {{serverData.title}}<br>
  completed is {{serverData.completed}}
</p>
<ng-template #loading>
	<div>
		<h3>Loading data from server....</h3>
	</div>
</ng-template>

Open in new window

and here is  ServerData.ts
export interface ServerData {
  userId: number,
  id: number,
  title: string,
  completed: boolean
}

Open in new window

Explore More ContentExplore courses, solutions, and other research materials related to this topic.