Use the http service in Angular 1 meant to deal with promises and defer, because it was based on APIs exposed by the $q service.
Angular 2 makes a step ahead and the new implementation of the http service involves the observable pattern, with the using of RxJS javascript library.
Why this big change? Because an observable is a powerful way to observe the behavior of a variable and its changes, for example when we assign a value or change it.
What we can do to use the http service efficiently is implement a typescript class that exposes the CRUD operation on a generic entity, based on a Web API.
Base class
This class exposes five basic methods to do simple CRUD operations; the first step is import the libraries:
import { Http, Response, Headers, RequestOptions } from "@angular/http"; import { Observable } from "rxjs/Observable";
We import a bunch of objects of the http angular library and the observable library.
Now we can implement the class:
export class WebApi<T> { protected url: string; protected options: RequestOptions; constructor(url: string, public http: Http) { this.url = url; let headers = new Headers({ "Content-Type": "application/json" }); this.options = new RequestOptions({ headers: headers }); } public GetAll(): Observable<T[]> { return this.http.get(this.url, this.options).map(this.extractData).catch(this.handleError); }; public Get(id: string): Observable<T> { return this.http.get(this.url + "/" + id, this.options).map(this.extractData).catch(this.handleError); } public Put(id: string, entity: T): Observable<boolean> { return this.http.put(this.url + "/" + id, JSON.stringify(entity), this.options).map(this.extractResponseStatus).catch(this.handleError); } public Post(entity: T): Observable<T> { return this.http.post(this.url, JSON.stringify(entity), this.options).map(this.extractData).catch(this.handleError); } public Delete(id: string): Observable<boolean> { return this.http.delete(this.url + "/" + id, this.options).map(this.extractResponseStatus).catch(this.handleError); } protected extractData(res: Response) { let body = res.json(); return body || {}; } protected handleError(error: any) { let errMsg = (error.message) ? error.message : error.status ? `${error.status} - ${error.statusText}` : 'Server error'; console.error(errMsg); return Observable.throw(errMsg); } private extractResponseStatus(res: Response) { return res.ok; } }
This is a typed class, with it we are able to define an instance of the class for a specific entity.
All the methods return an Observable property, dealing with the http service; every observable response uses a method to return the json part of the response and another method to handle and log response errors.
This is a class that will be used for our services.
The service
A specific service extends the base class and it can add some specific methods.
The implementation is look like this:
import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import { Customer } from "./customer.model"; import { WebApi } from "../shared/webapi"; @Injectable() export class CustomerService extends WebApi<Customer> { constructor(public http: Http) { super("/api/customers", http); } }
The service extends the WebApi typed class and injects the base url of the Web API and the http service instance.
Using
In a controller we can use the service to retrieve the list of the customers:
..... import { CustomerService } from "./customer.service"; ..... export class CustomerComponent implements OnInit { ..... constructor(private customerService: CustomerService, .....) {} ngOnInit() { ..... this.Load(); } public Load() { ..... this.customerService.GetAll().subscribe( (data) => { ..... this.customers = data; ..... }, (error) => this.alertService.Error(error)); } }
As you seen above, the GetAll method returns an observable property, so in order to retrieve the reponse, we need to subscribe to it.
The subscribe method can accepts two functions as parameters; the first one will be called if we’ll receive a successfully response; the second one will be executed if an error occurred.
The source code of this topic is available here.
Leave a Reply