6: Get Data from a Server
[examples/angular-tour-of-heroes] / src / app / hero.service.ts
1 import { Injectable } from '@angular/core';
2 import { Observable, of, EMPTY } from 'rxjs';
3 import { Hero } from './hero';
4 import { HEROES } from './mock-heroes';
5 import { HttpClient, HttpHeaders } from '@angular/common/http';
6 import { MessageService } from './message.service';
7 import { catchError, tap } from 'rxjs/operators';
8
9
10 @Injectable({
11   providedIn: 'root'
12 })
13 export class HeroService {
14
15   heroesUrl = 'api/heroes';  // URL to web api
16   httpOptions = {
17     headers: new HttpHeaders({ 'Content-Type': 'application/json' })
18   };
19
20   constructor(
21     private http: HttpClient,
22     private messageService: MessageService) { }
23
24   getHeroes(): Observable<Hero[]> {
25     this.log('fetching heroes...');
26     return this.http
27       .get<Hero[]>(this.heroesUrl)
28       .pipe(
29         tap((heroes: Hero[]) => this.log(`fetched ${heroes.length} heroes`)),
30         catchError(this.handleError<Hero[]>('getHeroes', []))
31       );
32   }
33
34   /** GET hero by id. Will 404 if id not found */
35   getHero(id: number): Observable<Hero> {
36     this.log(`requested hero id=${id}`);
37     const url = `${this.heroesUrl}/${id}`;
38     return this.http.get<Hero>(url).pipe(
39       tap(_ => this.log(`fetched hero id=${id}`)),
40       catchError(this.handleError<Hero>(`getHero id=${id}`))
41     );
42   }
43
44   /** PUT: update the hero on the server */
45   updateHero(hero: Hero): Observable<any> {
46     return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
47       tap(_ => this.log(`updated hero id=${hero.id}`)),
48       catchError(this.handleError<any>('updateHero'))
49     );
50   }
51
52   /**
53    * Handle Http operation that failed.
54    * Let the app continue.
55    * @param operation - name of the operation that failed
56    * @param result - optional value to return as the observable result
57    */
58   private handleError<T>(operation = 'operation', result?: T) {
59     return (error: any): Observable<T> => {
60
61       // TODO: send the error to remote logging infrastructure
62       console.error(error); // log to console instead
63
64       // TODO: better job of transforming error for user consumption
65       this.log(`${operation} failed: ${error.message}`);
66
67       // Let the app keep running by returning an empty result.
68       if (result === undefined) {
69         return EMPTY as Observable<T>;
70       } else {
71         return of(result as T);
72       }
73     };
74   }
75
76   /** Log a HeroService message with the MessageService */
77   private log(message: string) {
78     this.messageService.add(`HeroService: ${message}`);
79   }
80 }