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';
13 export class HeroService {
15 heroesUrl = 'api/heroes'; // URL to web api
17 headers: new HttpHeaders({ 'Content-Type': 'application/json' })
21 private http: HttpClient,
22 private messageService: MessageService) { }
24 getHeroes(): Observable<Hero[]> {
25 this.log('fetching heroes...');
27 .get<Hero[]>(this.heroesUrl)
29 tap((heroes: Hero[]) => this.log(`fetched ${heroes.length} heroes`)),
30 catchError(this.handleError<Hero[]>('getHeroes', []))
34 /** POST: add a new hero to the server */
35 addHero(hero: Hero): Observable<Hero> {
36 return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe(
37 tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
38 catchError(this.handleError<Hero>('addHero'))
42 /** GET hero by id. Will 404 if id not found */
43 getHero(id: number): Observable<Hero> {
44 this.log(`requested hero id=${id}`);
45 const url = `${this.heroesUrl}/${id}`;
46 return this.http.get<Hero>(url).pipe(
47 tap(_ => this.log(`fetched hero id=${id}`)),
48 catchError(this.handleError<Hero>(`getHero id=${id}`))
52 /** PUT: update the hero on the server */
53 updateHero(hero: Hero): Observable<any> {
54 return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
55 tap(_ => this.log(`updated hero id=${hero.id}`)),
56 catchError(this.handleError<any>('updateHero'))
60 /* GET heroes whose name contains search term */
61 searchHeroes(term: string): Observable<Hero[]> {
63 // if not search term, return empty hero array.
66 return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
68 this.log(`found heroes matching "${term}"`) :
69 this.log(`no heroes matching "${term}"`)),
70 catchError(this.handleError<Hero[]>('searchHeroes', []))
75 * Handle Http operation that failed.
76 * Let the app continue.
77 * @param operation - name of the operation that failed
78 * @param result - optional value to return as the observable result
80 private handleError<T>(operation = 'operation', result?: T) {
81 return (error: any): Observable<T> => {
83 // TODO: send the error to remote logging infrastructure
84 console.error(error); // log to console instead
86 // TODO: better job of transforming error for user consumption
87 this.log(`${operation} failed: ${error.message}`);
89 // Let the app keep running by returning an empty result.
90 if (result === undefined) {
91 return EMPTY as Observable<T>;
93 return of(result as T);
98 /** Log a HeroService message with the MessageService */
99 private log(message: string) {
100 this.messageService.add(`HeroService: ${message}`);