angularrxjshttpservice

Simplify API calls when using pipe and HttpService in Angular8


In most of my API calls I use this pattern:

  1. call server and pipe result

  2. Check for error and throw if needed

  3. map results from server

    public getItems() : Observable<Item[]> {

      return this.http.get<Item[]>>(environment.url + '/items').pipe(
    
             catchError((error:any)=> throwError('Failed getting items')),
    
             map((ret)=> this.mapResults(ret)));
    

    }

Is there a way to merge the catchError and map operators to a single operator ?

Something like this:

catchErrorAndMap("Message in case of error",itemForMapping)

itemForMapping will go into the mapping function. something like this?

 return this.http.get<Item[]>>(environment.url + '/items').pipe(
    
                catchErrorAndMap('Failed getting items'),ret));

Solution

  • Yes. An RxJS operator is just a function. So, you can write your own RxJS operators.

    There is an example here: https://netbasal.com/creating-custom-operators-in-rxjs-32f052d69457

    In the section entitled: "Creating Operators from Existing Operators".

    So you can create a catchErrorAndMap function that you can then use as an operator.

    Here is an example:

    export function catchErrorAndMap(errorMessage): OperatorFunction<User[], User[]> {
      return source =>
        source.pipe(
          catchError((error: any) => throwError(errorMessage)),
          map(items => items.map(item => ({ ...item, name: item.name + "'s"} as User)))
        );
    }
    

    This creates a function that takes in an Observable<User[]> and returns an Observable<User[]>. You'd need to modify it as needed for your project. (Probably Item[]).

    It then pipes the source (which is the emitted item from the source stream) through the desired operators.

    In this example, I used a map operation appropriate for my data. You could of course change it to your this.mapResults().

    You'd call this operator just like any other pipe operator:

      users$ = this.http
        .get<User[]>(this.userUrl)
        .pipe(catchErrorAndMap("Error Occurred"));