Full Angular HttpClient get

Source: https://www.concretepage.com/angular-2/angular-httpclient-get-example

This page will walk through Angular HttpClient.get example. HttpClient has been introduced in Angular 4.3 version. HttpClient is smaller, easier and more powerful library for making HTTP requests. To use HttpClient we need to import HttpClientModule in our application module and then we can inject HttpClient in our components or services. HttpClient has methods such as getpostdeleteput etc. We will discuss here get method.HttpClient.get constructs an Observable with configured GET request and when the Observable instance is subscribed, GET request is executed on the server. Here on this page we will provide the use of HttpClient.get in detail with error handling. For Web Service test URL we will use Angular In-Memory Web API. Now find the complete example step by step.

Technologies Used

Find the technologies being used in our example. 
1. Angular 5.0.0 
2. Angular CLI 1.5.4 
3. TypeScript 2.4.2 
4. Node.js 6.11.0 
5. NPM 3.10.10 
6. In-Memory Web API 0.5.3

HttpClient.get

HttpClient serves the purpose to perform HTTP requests. HttpClient is injectable class. To perform http GET request, HttpClient provides HttpClient.get method that accepts URL and options for parameter, header etc and returns an Observable instance. When we subscribe Observable then GET request is executed on the server. Find the syntax of HttpClient.get from Angular doc.

get(url: string, options: {
    headers?: HttpHeaders | {
        [header: string]: string | string[];
    };
    observe?: HttpObserve;
    params?: HttpParams | {
        [param: string]: string | string[];
    };
    reportProgress?: boolean;
    responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
    withCredentials?: boolean;
} = {}): Observable<any> 
We can see that HttpClient.get accepts URL and other options such as parameter, headers etc. HttpClient.gethas following options to request http GET method. 

headers: It is of HttpHeaders types. It sets headers for the http GET request. 

observe: It defines whether we want complete response or body only or events only. We need to assign values for observe property such as response for complete response, body for response with body and events for response with events. 

params: It is of HttpParams type. It sets parameters in URL for http GET request. 

reportProgress: It is of boolean type. It is useful when we are requesting blob data. Setting reportProgress value as true we can know progress report for our HttpClient.get request. 

responseType: It is used to define response type of HttpClient.get request. Its values can be arraybufferblobjson and text

withCredentials: It is of boolean type. If the value is true then HttpClient.get will request data with credentials.

The response type of HttpClient.get is Observable i.e. provided by RxJS library. Observable is a representation of any set of values over any amount of time.

HttpClientModule

To use HttpClient we need to import HttpClientModule in our application module. Find the code snippet.

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [     
      HttpClientModule,
      ------
 
  ],
  ------
})
export class AppModule { } 
Now we can inject HttpClient in our components or services.

Injecting HttpClient

We inject HttpClient using constructor into our component or service. HttpClient is imported from @angular/common/http library as following.

import { HttpClient } from '@angular/common/http'; 
Find the constructor to inject HttpClient.

constructor(private http: HttpClient) { 
} 
Now we are ready to call HttpClient methods using http instance. For example, find the code below.

getWriterWithFavBooks(): Observable<any> {
       return this.http.get(this.writerUrl);
} 

Requesting JSON using HttpClient.get

Find the sample JSON data.
{ 
    writerId: 11, writerName: 'Mahesh',
    books: [
      { id: '103', name: 'Angular Tutorial', category: 'Angular', year: '2016' }, 
      { id: '104', name: 'Core Java Tutorial', category: 'Java', year: '2015' }
    ]
} 
Suppose we have following URL to access the JSON data.
writerUrl = "/api/writer"; 
Now we can access JSON using HttpClient.get as following.
writerUrl = "/api/writer";
getWriterWithFavBooks(): Observable<any> {
      return this.http.get(this.writerUrl, {responseType: 'json'});
} 
If response type is JSON then using responseType: 'json' is optional we can also write it as following.
getWriterWithFavBooks(): Observable<any> {
      return this.http.get(this.writerUrl);
} 
Now subscribe to instance of Observable for actual hit of request to server and get response.
getWriterWithFavBooks() {
  this.writerService.getWriterWithFavBooks().subscribe(
      data => { 
       this.favBooks = data['books'];
   }
      );
} 
If we want Typechecking of response then we can do it by using type parameter. Suppose we have following interfaces.
export interface Book {
   id: number;
   name: string;
   category: string;
   year: string;
}
export interface Writer {
   writerId: number;
   writerName: string;
   books: Book[];
} 
We can tell the HttpClient.get to return response as Writer. Find the code snippet.
getFavoriteWriter(): Observable<Writer> {
       return this.http.get<Writer>(this.writerUrl, {responseType: 'json'});
} 
When we use http.get<Writer>(...) then it returns the instance of Observable<Writer> type. Now subscribe to Observable<Writer> to get instance of Writer.
getFavoriteWriter() {
    this.writerService.getFavoriteWriter().subscribe(
       data => { 
          this.favWriter = data;
   console.log(this.favWriter.books);
  }
       );    
} 
Display data in HTML template as following.
<div *ngIf="favWriter">
  Writer Id: <b>{{favWriter.writerId}}</b>, Writer Name: <b>{{favWriter.writerName}}</b>
  <ul>
    <li *ngFor="let book of favWriter.books" >
      Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
    </li>
  </ul>
</div> 

Using async Pipe with Observable

HttpClient.get returns instance of Observable. To display this data either we can subscribe to Observable or we can use async pipe with Observable. We have already provided sample code above to display data by subscribing Observable. Here find the code to display data using async pipe. Suppose we have following JSON data.
[
     { id: '103', name: 'Angular Tutorial', category: 'Angular', year: '2016' }, 
     { id: '104', name: 'Core Java Tutorial', category: 'Java', year: '2015' }
] 
The JSON data is of Book array type. We will provide type parameter as Book[]. Now find the code for HttpClient.get.
bookUrl = "/api/books"; 
getBooks(): Observable<Book[]> {
     return this.http.get<Book[]>(this.bookUrl);
} 
Now access the method and assign the value to Observable property.
obsBooks: Observable<Book[]>
getBooks() {
      this.obsBooks = this.writerService.getBooks();
} 
Use async pipe to display data in HTML template.
<ul>
  <li *ngFor="let book of obsBooks | async" >
    Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
  </li>
</ul> 

Requesting Text data using HttpClient.get

To access text data using HttpClient.get we need to use responseType: 'text'. Suppose we have following text.
Welcome to the Angular world! 
Find the URL to access the above text.
textUrl = "/api/message"; 
Now use HttpClient.get with responseType: 'text' as following.
getTextMsg(): Observable<string> {
     return this.http.get(this.textUrl, {responseType: 'text'});
} 
To display data, we can use either async pipe with Observable or we can subscribe it to get text data. Find the sample example.
obsTextMsg: Observable<string>
getTextMsg() {
  this.obsTextMsg = this.writerService.getTextMsg();
  this.writerService.getTextMsg().subscribe(
      msg => console.log(msg)
  );
} 
Observable instance i.e. obsTextMsg can directly be displayed on HTML template using async pipe as following.
<h3 *ngIf="obsTextMsg | async as message"> {{ message }} </h3> 

HttpParams and HttpHeaders

Angular provides HttpParams class to use parameters and it provides HttpHeaders class to use headers with HttpClient.get request. Both HttpParams and HttpHeaders classes are immutable and imported from @angular/common/http library. Both have methods such as set and appendset constructs a new body with a new value and append constructs a new body with an appended value. 
We will import HttpParams and HttpHeaders as following.
import { HttpHeaders, HttpParams } from '@angular/common/http'; 
Now find sample example to use HttpParams and HttpHeaders with HttpClient.get request.
filterBooks(category: string, year: string): Observable<Book[]> {
   let httpHeaders = new HttpHeaders()
                         .set('Accept', 'application/json');
   let httpParams = new HttpParams()
                        .set('category', category)
                 .set('year', year);
   console.log(httpParams.toString());
   console.log(httpHeaders.keys());
   return this.http.get<Book[]>(this.bookUrl, {
          headers: httpHeaders,
          params: httpParams, 
          responseType: 'json'
  });
} 

HttpClient.get with observe Property

HttpClient.get method can use observe property to define whether we want complete response or body only or events only. We need to assign values for observe property such as 
observe : 'response' for complete response. 
observe : 'body' for response with body. 
observe : 'events' for response with events. 

Suppose we want complete response of our request then we will use observe property with HttpClient.get as following.
getFullResponseForWriter(): Observable<HttpResponse<any>> {
     return this.http.get(this.writerUrl, {
     observe: 'response'
    });
} 
HttpResponse is from @angular/common/http library. Now we will fetch body as well as headers of the response as following.
writer: Writer;
getWriter() {
  this.writerService.getFullResponseForWriter().subscribe(
      res => { 
       this.writer = res.body;
            console.log(this.writer.books);
           console.log(res.headers.get('Content-Type'));     
      },
      err => {
       console.log(err);
      }
   );    
} 

Error Handling

To handle error, Angular provides HttpErrorResponse class from @angular/common/http library. HttpErrorResponsecontains useful information regarding error. The second parameter in subscribe() is for error. We can log error as following.
getFavoriteWriter() {
  this.writerService.getFavoriteWriter().subscribe(
      data => { 
   this.favWriter = data;
      },
      err => {
   console.log(err);
      }
   );    
} 
HttpClient.get can face two types of errors. 
a. If backend returns unsuccessful response codes such as 404, 500 etc then HttpClient.get will throw error with backend response code. 
b. If something goes wrong client-side, for example, an exception is thrown by RxJS operators or if network error prevents the request from completing successfully then actual Error object is thrown by HttpClient.get

We can check if error is of Error type or not by using HttpErrorResponse and accordingly log the error messages.HttpErrorResponse can be imported from @angular/common/http library as following.
import { HttpErrorResponse } from '@angular/common/http'; 
Now find the sample code to log error.
getFavoriteWriter() {
  this.writerService.getFavoriteWriter().subscribe(
      data => { 
       this.favWriter = data;
      },
      (err: HttpErrorResponse) => {
   if (err.error instanceof Error) {
                 //A client-side or network error occurred.
   console.log('An error occurred:', err.error.message);
   } else {
                 //Backend returns unsuccessful response codes such as 404, 500 etc.
   console.log('Backend returned status code: ', err.status);
   console.log('Response body:', err.error);
   }
       }
   );    
} 

RxJS retry() to Handle Error

Some errors can be handled by just retrying request such as if errors are transient and unlikely to repeat. For example if we have slow network error and our request could not become successful then there are the chances to make request successful if request is retried. 
To retry request automatically RxJS provides retry() operator that is called on Observableretry() operator accepts number argument, suppose we pass argument as retry(3) then the request will be retried for 3 times.retry() is imported from RxJS as following.
import 'rxjs/add/operator/retry'; 
Find the sample example to use retry().
getFavoriteWriter() {
  this.writerService.getFavoriteWriter().retry(3).subscribe(
      data => { 
       this.favWriter = data;
      },
      (err: HttpErrorResponse) => {
   if (err.error instanceof Error) {
   console.log('An error occurred:', err.error.message);
   } else {
   console.log('Backend returned status code: ', err.status);
   console.log('Response body:', err.error);
   }
       }
   );    
} 

Angular In-Memory Web API to Test Application

To test application we need Web Service URL. Angular provides In-Memory Web API that will provide Web Service URL. We can configure URLs with dummy data using In-Memory Web API. Find the steps to use Angular In-Memory Web API. 
1. Open the command prompt and navigate to the directory where package.json resides and run following command.
npm i angular-in-memory-web-api@0.5.3 --save 
2. Create a class that will implement InMemoryDbService. Define createDb() method with some dummy data. 
test-data.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';

export class TestData implements InMemoryDbService {
  createDb() {
    //JSON data  
    let bookDetails = [
      { id: '101', name: 'Angular 2 by Krishna', category: 'Angular', year: '2015' },
      { id: '102', name: 'AngularJS by Krishna', category: 'Angular', year: '2015' },
      { id: '103', name: 'Angular 2 by Vishnu', category: 'Angular', year: '2016' }, 
      { id: '104', name: 'Core Java by Vishnu', category: 'Java', year: '2016' },
      { id: '105', name: 'JSP & Servlet by Vishnu', category: 'Java', year: '2016' },
      { id: '106', name: 'JPA by Vishnu', category: 'Java', year: '2016' },
      { id: '107', name: 'Hibernate by Krishna', category: 'Hibernate', year: '2015' }
    ];
    //JSON data
    let writerDetails = 
      { 
     writerId: 11, writerName: 'Mahesh',
     books: [
    { id: '103', name: 'Angular Tutorial', category: 'Angular', year: '2016' }, 
    { id: '104', name: 'Core Java Tutorial', category: 'Java', year: '2015' }
     ]
      };
    //Text data
    let welcomeMsg = "Welcome to the Angular world!";
 
    return { books: bookDetails, writer: writerDetails, message: welcomeMsg };
  }
} 
We will get following Web Service URLs.
/api/books
/api/writer
/api/message 
3. Before using In-Memory Web API we need to import InMemoryWebApiModule in application module and configure TestData class as following.
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TestData } from './test-data';

@NgModule({
  imports: [     
      ------
      InMemoryWebApiModule.forRoot(TestData)  
  ],
  ------
})
export class AppModule { } 
Find the link for more information on In-Memory Web API.

Complete Example

Find the project structure.
my-app
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--book.ts
|   |   |--writer.ts
|   |   |--writer.service.ts
|   |   |--writer.component.ts
|   |   |--writer.component.html
|   |   |
|   |   |--test-data.ts
|   |   |
|   |   |--app.component.ts
|   |   |--app.module.ts 
|   | 
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json 
Now find the complete code. 
book.ts
export interface Book {
   id: number;
   name: string;
   category: string;
   year: string;
} 
writer.ts
import { Book } from './book';

export interface Writer {
   writerId: number;
   writerName: string;
   books: Book[];
} 
writer.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Book } from './book';
import { Writer } from './writer';

@Injectable()
export class WriterService {
 
    constructor(private http: HttpClient) { }
 
    textUrl = "/api/message";
    getTextMsg(): Observable<string> {
        return this.http.get(this.textUrl, {responseType: 'text'});
    }  
 
    bookUrl = "/api/books"; 
    getBooks(): Observable<Book[]> {
        return this.http.get<Book[]>(this.bookUrl);
    }
    filterBooks(category: string, year: string): Observable<Book[]> {
 let httpHeaders = new HttpHeaders()
                   .set('Accept', 'application/json');
        return this.http.get<Book[]>(this.bookUrl + '?category=' + category + '&year=' + year, {
          headers: httpHeaders,
          responseType: 'json'
  });
    }
 
    writerUrl = "/api/writer";
    getWriterWithFavBooks(): Observable<any> {
        return this.http.get(this.writerUrl, {responseType: 'json'});
    } 
    getFavoriteWriter(): Observable<Writer> {
        return this.http.get<Writer>(this.writerUrl, {responseType: 'json'});
    }  
    getFullResponseForWriter(): Observable<HttpResponse<any>> {
        return this.http.get(this.writerUrl, {
      observe: 'response'
     });
    } 
 
    myUrl = "/api/invalid";
    getDataForUrl(): Observable<any> {
 return this.http.get(this.myUrl);
    } 
} 
writer.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/retry';
import { HttpErrorResponse } from '@angular/common/http';
import { FormBuilder } from '@angular/forms';
import { WriterService } from './writer.service';
import { Book } from './book';
import { Writer } from './writer';

@Component({
   selector: 'app-writer',
   templateUrl: './writer.component.html'
})
export class WriterComponent implements OnInit { 
   obsTextMsg: Observable<string>
   obsBooks: Observable<Book[]>
   books: Book[];
   favBooks: Book[];
   favWriter: Writer;
   writer: Writer;
   
   categories = [ 
  {category: 'Angular'},
  {category: 'Hibernate'},
  {category: 'Java'}
   ];
   years = [ 
  {year: '2015'},
  {year: '2016'}
   ];   
   
   constructor(private writerService: WriterService,
               private formBuilder:FormBuilder) { }
   
   ngOnInit() {
   this.getTextMsg();
   this.getBooks(); 
          this.getWriterWithFavBooks(); 
          this.getFavoriteWriter();   
          this.getWriter();   
   this.getData();
   }
   
   bookForm = this.formBuilder.group({
          category: '',
          year: ''
   });
   
   onFormSubmit() {
   let category = this.bookForm.get('category').value;
          let year = this.bookForm.get('year').value;   
          this.filterBooks(category, year);
   }   
   
   getTextMsg() {
   this.obsTextMsg = this.writerService.getTextMsg();
   this.writerService.getTextMsg().subscribe(
       msg => console.log(msg)
   );
   }   
   getBooks() {
          this.obsBooks = this.writerService.getBooks();
   }
   filterBooks(category: string, year: string) {
   this.writerService.filterBooks(category, year)
      .subscribe(data => this.books = data);
   }   
   getWriterWithFavBooks() {
   this.writerService.getWriterWithFavBooks().subscribe(
       data => { 
   this.favBooks = data['books'];
       }
   );
   }
   getFavoriteWriter() {
   this.writerService.getFavoriteWriter().retry(2).subscribe(
       data => { 
    this.favWriter = data;
    console.log(this.favWriter.books);
       },
       (err: HttpErrorResponse) => {
   if (err.error instanceof Error) {
                     //A client-side or network error occurred.     
       console.log('An error occurred:', err.error.message);
   } else {
                     //Backend returns unsuccessful response codes such as 404, 500 etc.     
       console.log('Backend returned status code: ', err.status);
       console.log('Response body:', err.error);
   }
       }    
   );    
   }
   getWriter() {
   this.writerService.getFullResponseForWriter().subscribe(
       res => { 
           this.writer = res.body;
    console.log(this.writer.books);
    console.log(res.headers.get('Content-Type'));     
       },
       err => {
    console.log(err);
       }
   );    
   } 
   getData() {
   this.writerService.getDataForUrl().retry(3).subscribe(
       res => {
   console.log(res);  
       },
       (err: HttpErrorResponse) => {
  if (err.error instanceof Error) {
                   //A client-side or network error occurred.      
     console.log('An error occurred:', err.error.message);
         } else {
                   //Backend returns unsuccessful response codes such as 404, 500 etc.      
     console.log('Backend returned status code: ', err.status);
     console.log('Response body:', err.error);
  }
       }
   );
   }    
} 
writer.component.html
<h3 *ngIf="obsTextMsg | async as message"> {{ message }} </h3>

<h3>Book Details</h3>
<ul>
  <li *ngFor="let book of obsBooks | async" >
    Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
  </li>
</ul>

<h3>Filter Books</h3>
<form [formGroup]="bookForm" (ngSubmit)="onFormSubmit()">
 Select Category:
 <select formControlName="category">
  <option *ngFor="let cat of categories" [ngValue]="cat.category">
    {{ cat.category }}
  </option>
 </select>
 Select Year:
 <select formControlName="year">
  <option *ngFor="let yr of years" [ngValue]="yr.year">
    {{ yr.year }}
  </option>
 </select>
 <button>SUBMIT</button>
</form>
Result:
<ul>
  <li *ngFor="let book of books" >
    Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
  </li>
</ul>

<h3>Favorite Books</h3>

<ul>
  <li *ngFor="let book of favBooks" >
    Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
  </li>
</ul>

<h3>Favorite Writer Details</h3>
<div *ngIf="favWriter">
  Writer Id: <b>{{favWriter.writerId}}</b>, Writer Name: <b>{{favWriter.writerName}}</b>
  <ul>
    <li *ngFor="let book of favWriter.books" >
      Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
    </li>
  </ul>
</div>

<h3>Writer Details</h3>
<div *ngIf="writer">
  Writer Id: <b>{{writer.writerId}}</b>, Writer Name: <b>{{writer.writerName}}</b>
  <ul>
    <li *ngFor="let book of writer.books" >
      Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
    </li>
  </ul>
</div> 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
 <app-writer></app-writer>
    `
})
export class AppComponent { 

} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent }  from './app.component';
import { WriterComponent }  from './writer.component';
import { WriterService } from './writer.service';

//For InMemory testing
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { TestData } from './test-data';

@NgModule({
  imports: [     
      BrowserModule,
      HttpClientModule,
      ReactiveFormsModule,
      InMemoryWebApiModule.forRoot(TestData)  
  ],
  declarations: [
      AppComponent,
      WriterComponent
  ],
  providers: [
      WriterService
  ],
  bootstrap: [
      AppComponent
  ]
})
export class AppModule { } 

Run Application

To run the application, find the steps. 
1. Download source code using download link given below on this page. 
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link
3. Install angular-in-memory-web-api@0.5.3 
4. Run ng serve using command prompt. 
5. Access the URL http://localhost:4200 
Find the print screen of the output.
Angular HttpClient get Example

References

Không có nhận xét nào:

Is it okay to use both fetchpriority="high" and loading="eager" in img tag?

 https://stackoverflow.com/questions/77744344/is-it-okay-to-use-both-fetchpriority-high-and-loading-eager-in-img-tag Yes Fetchpriority and l...