CRM App - Part 6 Angular’s Http Client Module

Overview

Time: 5min

In this lesson, we will use Angular's Http Client Module to make a real request.

Learning Outcomes:

  • How to make Http requests to a web server
  • How to subscribe to an observable
  • How to manage error handling
  • How to use RXJS operators through .pipe() function

Call a real API from CompanyService

Time: 10min

The CompanyService currently returns an in-memory list.

The following changes will enable the service to call a real back-end, hosted on Microsoft Azure.

  • Add the HttpClientModule to your app.module. From version 1.1 of the angular cli, the HttpClientModule is not included by default.

src/app/app.module.ts

import { HttpClientModule } from '@angular/common/http';
 imports: [
    BrowserModule,
    AppRoutingModule,
    NgbModule,
    HttpClientModule
  ],
  • Import the Http, Headers, RequestOptions and Observable into the service

src/app/company/company.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
  • Add a property for the API_BASE and inject the Http module into the component.

src/app/company/company.service.ts

@Injectable()
export class CompanyService {
    API_BASE = 'https://app-fbc-crm-api-prod.azurewebsites.net/api';

    constructor(private httpClient: HttpClient){}

}
  • Update the getCompanies method to call the API endpoint on Azure
 getCompanies(): Observable<Company[]> {
    return this.httpClient.get<Company[]>(`${this.API_BASE}/company`);
  }
  • update the component to call the updated service

src/app/company/company-list/company-list.component.ts

  getCompanies() {
    this.companyService.getCompanies()
      .subscribe(companies => this.companies = companies);
  }
  • Refresh your browser. The list of companies now being shown is coming from the Microsoft Azure API!

Add error handling to the service

Time: 5 min
  • Import the RxJS operators at the top of the file.
import { catchError } from 'rxjs/operators';
  • add a catchError to the HTTP request in case of an error

src/app/company/company.service.ts

  getCompanies(): Observable<Company[]> {
    return this.httpClient.get<Company[]>(`${this.API_BASE}/company`)
      .pipe(catchError(this.errorHandler));
  }
  • add the error handler to the service

src/app/company/company.service.ts


  private errorHandler(error: Error): Observable<Company[]> {
    console.error('implement custom errort handler here', error);
    return new Observable<Company[]>();
  }

 // 1/ return union type so 400(bad request), 422(unprocessable) and 404(notfound)
 // 2/ return an empty observable means it is completed
 // 3/ use http interceptor and move this logic to a globale handler vs 500(server error)

}


Using the async pipe

Time: 5 min

Introduced with Angular 4, the async pipe provides a way for us to bind observables directly into our templates without manually subscribing in our components.

  • Add an Observable import to CompaniesList component
import { Observable } from 'rxjs';
  • update the type of the companies collection to be an Observable. Note the $ suffix on the property name. This is a convention used to label observable properties.
public companies$!: Observable<Company[]>;
  • Note the "!" (called a non-null assertion operator, or "bang" operator). This is a Typescript feature, not Angular.

  • update the getCompanies() method to remove the subscription and pass the observable directly to companies$

getCompanies() {
    this.companies$ = this.companyService.getCompanies();
}
  • update the template to use the async pipe.
<tr *ngFor="let company of companies$ | async">

Async Pipe Explained

Every subscription left against an observable uses a small amount of memory. Also every subscription will cause callbacks to be executed. So it's important to manage the lifecycle of our subscriptions. One way of managing unsubscribes is to keep a reference to the subscription and manually unsubscribe when a component is unloaded. This requires writing a few lines of code - which is why the async pipe was added.

Pipe operators (using the | char) are functions that can tranform data inside a templte. A classic example is the date pipe that allows date objects to be formatted for display. The | async pipe has been specifically made for safely dealing with observables.

  • The observable is subscribed to
  • Any changes raised by the observable are updated in the template
  • If the component is unloaded, the subscription is automatically unsubscribed.

Using RXJS .pipe()

Time: 5 min

RxJS operators can be applied anywhere on Observables to perform operation. We've seen how to add a "catchError" to handle our errors in the Service. We can also add pipe() in our Component to perform any operation required.

  • Add 'tap' & 'finalise' operators both in Service and Component :

src/app/company/company.service.ts

    import { tap, finalize } from 'rxjs/operators';
    
    ...
    
    getCompanies(): Observable<Company[]> {
        return this.httpClient.get<Company[]>(`${this.API_BASE}/company`)
          .pipe(
            tap(x => console.log('TAP - Service', x)),
            catchError(this.errorHandler)
          );
      }

src/app/company/company-list/company-list.component.ts

    import { tap, finalize } from 'rxjs/operators';
    
    ...

     ngOnInit() {
        this.companies$ = this.companyService.getCompanies()
          .pipe(
            tap(x => console.log('TAP - Component', x)),
            finalize(() => console.log('Finalize: Complete'))
          );
      }

'tap' operator let you Transparently perform actions or side-effects, such as logging.
(https://www.learnrxjs.io/operators/utility/do.html)

'finalize' let you call a function (callback) when the observable completes.
(https://www.learnrxjs.io/operators/utility/finalize.html)

You can chain as many RxJS operators as you need to implement any complex scenario.

EXTRA Subscription management

https://medium.com/@gergo.koncz/rxjs-subscription-management-in-angular-f242180c8173

Read this article to know more about subscription management in Angular

https://github.com/ngneat/until-destroy

My favourite: NgNeat Until-Destroy <3

EXTRA RxMarbles

Time: 10 min
  • RxMarbles (https://rxmarbles.com/) is an awesome website that lets you play with an interactive representation of all Rx Operators
  • It is very useful in understanding how the most common RxJS operators work