This tutorial is adapted from Web Age course Comprehensive Angular 10 Programming Training.
1.1 The Angular HTTP Client
The Angular HTTP Client provides a simplified API for network communication. It is a wrapper over the JavaScript XMLHttpRequest API. The API is asynchronous. JavaScript is single-threaded. Doing a blocking synchronous HTTP call will otherwise freeze the UI. It supports making HTTP requests (GET, POST, etc.), working with request and response headers, asynchronous programming. It makes use of the rxjs async library Observable object.
1.2 Using The HTTP Client – Overview
The core client API is available from the HttpClient Angular service class. This is available from the HttpClientModule Angular module.
- Import HttpClientModule from your application module.
A Data Service is created that makes network requests:
- Use various methods of HttpClient to make network calls. They return an Observable object. Usually, this Observable is returned from the service method.
An Angular component is used to display the response data:
-
- The data service is injected into the constructor
- The component calls a method of the data service and obtains an Observable object.
- The component then “subscribes” to the Observable to receive the response from the HTTP call.
- The component’s template displays the data
1.3 Importing HttpClientModule
import {HttpClientModule} from '@angular/common/http'; @NgModule({ imports: [ BrowserModule, HttpClientModule ], ...})
Importing HttpClientModule
Note that HttpClientModule configures HttpClient as a provider. You don’t have to do this again from your application module. As a result, HttpClient is now injectable anywhere in your application.
1.4 Service Using HttpClient
Sample Service Code (“people.service.ts”):
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; export class Person {id:number, name:string ...} @Injectable(...) export class PeopleService{ constructor(private http: HttpClient){} getPerson(id:number) : Observable<Person> { return this.http.get<Person>(`/app/person/${id}`) } getAllPersons() : Observable<Person[]> { return http.get<Person[]>(`/app/person`) } }
1.5 Making a GET Request
- Call the get() method of HttpClient service.
- All network call methods like get(), post(), put() return an Observable.
- There are many overloaded versions of the get() call. Some are:
let obs:Observable<Object> = http.get(url) //Strong typing let obs:Observable<Person> = http.get<Person>(url)
- For the get() calls it is recommended you use the strongly typed version (second one from above).
- The get() method returns an Observable immediately. One needs to subscribe to the Observable to obtain the response data asynchronously.
Notes:
As they are used with the Angular HttpClient object Observable objects can be thought of as the glue that connects network requests with data consumers. There are several aspects to this relationship that our discussion will cover one at a time. From the current slide, we see that http requests return Observable objects that we can assign to a variable for later use. In the next slide, we will take a look at how Observable objects are used.
1.6 What does an Observable Object do?
Angular uses the Reactive Extensions for JavaScript (RxJS) implementation of the Observable object. Observable objects provide a convenient way for applications to consume asynchronous data/event streams. Observable objects are exposed to events which they then make available to consumers. Applications consume events by subscribing to the Observable object. The Observable object can be used to transform data before returning it to a consumer if needed.
http://reactivex.io/intro.html
1.7 Using the Service in a Component
1.8 The PeopleService Client Component
import { Component, OnInit } from '@angular/core'; import { PeopleService, Person } from './people.service'; @Component({ selector: 'app-people', template: ` <p *ngFor='let person of list' >{person.name}}</p>` }) export class PeopleComponent implements OnInit { list: Person[] constructor(private peopleService: PeopleService ){} ngOnInit() { this.peopleService.getAllPersons().subscribe( (data: Person[]) => this.list = data ) } }}
1.9 Error Handling
- Two types of errors can happen during a network call:
- No network connection can be made to the server.
- The server returns an invalid response code in 4XX and 5XX range.
- A subscriber can handle these errors by supplying an error handler function to subscribe().
ngOnInit() { this.peopleService.getAllPersons().subscribe( (data: Person[]) => this.list = data, (error:HttpErrorResponse) => console.log(error) ) }
1.10 Customizing the Error Object
-
- A service may decide to offer more meaningful errors in a custom error object instead of the default HttpErrorResponse. You can intercept an error with the
catchError()
-
- operator and supply a custom error object using
throwError()
-
- .
The following transforms the error object from HttpErrorResponse to a string.
import {Observable, throwError} from 'rxjs' import {catchError} from 'rxjs/operators' export class PeopleService { constructor(httpClient: HttpClient){} getAllPersons() : Observable<Person[]> { return httpClient .get<Person[]>(`/app/person`) .pipe( catchError(error => throwError("There was a problem with the network")) ) } } //The component ngOnInit() { this.peopleService.getAllPersons().subscribe( (data: Person[]) => this.list = data, (errMsg:string) => alert(errMsg)) }
1.11 Making a POST Request
Supply the request body as the second argument to the post() method.
createPerson(person:Person) : Observable { return this.http.post("/app/person", person) }
If a POST request returns data in the response body, you can make a more type-safe call.
createPerson(person:Person) : Observable<AddPersonResult> { return this.http.post<AddPersonResult>("/app/person", person) } //The component this.peopleService.createPerson(...) .subscribe((result: AddPersonResult) => {...})
1.12 Making a PUT Request
- Supply the request body as the second argument to the put() method.
updatePerson(person:Person) : Observable { return this.http.put("/app/person", person) }
- If a PUT request returns data in the response body, you can make a more type-safe call.
updatePerson(person:Person) : Observable<UpdateResult> { return this.http.put<UpdateResult>("/app/person", person) } //The component this.peopleService.updatePerson(...) .subscribe((result: UpdateResult) => {...})
1.13 Making a DELETE Request
- A DELETE request does not take any body
deletePerson(id:number) : Observable { return this.http.delete(`/app/person/${id}`) }
- If a DELETE request returns data in the response body, you can make a more type safe call.
deletePerson(id:number) : Observable<DeleteStatus> { return this.http.delete<DeleteStatus>(`/app/person/${id}`) } //The component this.peopleService.deletePerson(12) .subscribe((result: DeleteStatus) => {...})
1.14 Summary
- What is the Angular HTTP Client
- Importing HttpClientModule
- Making Get/ Post Calls
- Working with Observables