Angular Services

What is Services in angular2?

• Services in Angular 2 are JavaScript functions, which are responsible for performing a single task.
• Services have their associated properties and methods, which can be included in the component or other Service.
• Services are the best way to share information among classes that don't know each other.
• Service is the best place from where we can bring our external Data to our app or do some repetitive task.
• Service can be shared between as many as Components we want.
• In real practice data comes from Server (e.g. JSON file) and Service is the best way to handle this.
• It is a mechanism used to share functionalities over Components when a component needs any service we can simply inject it.
• Angular distinguishes components from services to increase modularity and reusability.
• In Angular, a service is basically set of functionalities that we want to be available to multiple components. It's just an easy way to wrap up some functionality.
 Syntax to generate services using CLI command -
ng generate service myservicename
 Three steps are required to create an Angular 2 Service.
1. Import the injectable member.
2. Add the @Injectable Decorator.
3. Export Service class.
How can we mark a class as a Service?
• We need to declare a Decorator called Injectable.
• This will make our (service) class injectable in other components in our application.
• We can now get an instance of our Service Class in another Class.
• Inside our service, we have a method. We use inside this method a promise/observable to return the value
• Angular services are injectable and injector can inject it in any component in our angular application.
• When we add our service in provider’s metadata of @NgModule in module file then the service becomes available globally in the application.
• To get instance of service in our component, we need to create a constructor with arguments of our service types in private scope.
• When we use @Injectable() decorator in service at class level then angular injector considers the service available to inject.
• A service contains methods that can be used by any components.
 Steps to Create Angular Service-
Step 1 − Create a separate class which has the injectable decorator. The injectable decorator allows the functionality of this class to be injected and used in any Angular module.

@Injectable() export class classname { }

Step 2 – In our appComponent module or the module in which we want to use the service, we need to define it as a provider in the @Component decorator.

@Component ({ providers : [classname] })

Step 3 - Inject service in Component. To get service available in our component we need to create a constructor with an argument of our service type in private scope.

@Component({ selector: 'store-app', templateUrl: './store.component.html' }) export class StoreComponent { constructor(private classname: Classname) { } }

When component is loaded, service will be injected by the injector. Now we are ready to call service methods in our component. our service instance is studentService that will be used to call methods of StudentService service.
Step 4 - Using the Service method and properties in component.

ngOnInit() { this.title = this.classname.someMethod(); }

 Example of Services -

example.service.ts: import { Injectable } from '@angular/core'; @Injectable() export class ExampleService { someMethod() { return 'Hey!'; } } app.component.ts: import { Component } from '@angular/core'; import { ExampleService } from './example.service'; @Component({ selector: 'my-app', template: '

{{ title }}

', providers: [ExampleService] }) export class AppComponent { title: string; constructor(private exampleService: ExampleService) { } ngOnInit() { this.title = this.exampleService.someMethod(); } }

Include a service in the app.module.ts in the providers property of the app.module.ts @NgModule metadata.

app.module.ts: import { ExampleService } from './example.service'; @NgModule({ //other metadata properties providers: [ExampleService] })

Output- This will result in "Hey!" showing up within the h1 tag.

HTTP

• HTTP is one of the Protocols used to allow a browser to communicate with a server and vice versa.
• Http Service will help us to fetch external data, modify data, delete data , post to it etc. We need to import the http module to make use of the http service.
• HttpClient is Angular’s mechanism for communicating with a remote server over HTTP.
• It fetch a profile from the Real-world API.
• Angular provides us with its own service called HttpClient for making requests to servers
• HttpClient calls are wrapped within services instead of being used in Components directly.
• This allows for greater flexibility for our application structure as we can reuse our calls throughout the app, as well the ability to implement more advanced features such as caching.
• Advanced features can also be enabled using Http Interceptors.
• HTTP Interception is a major feature of @angular/common/http. With interception, we declare interceptors that inspect and transform HTTP requests from our application to the server. The same interceptors may also inspect and transform the server's responses on their way back to the application. Multiple interceptors form a forward-and-backward chain of request/response handlers.
 To make HttpClient available everywhere in the app-

1) Open the root AppModule. 2) Import the HttpClientModule symbol from @angular/common/http. app.module.ts import { HttpClientModule } from '@angular/common/http';

3) Add it to the @NgModule.imports array
4) Make request to an API that returns an observable. Then, subscribe to the returned observable to use the results in your application.
 Below is the HTTP signature as is in Angular 2 source –
1) request(url: string | Request, options?: RequestOptionsArgs): Observable ;
Performs any type of http request. First argument is required, and can either be a url or a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions} object can be provided as the 2nd argument. The options object will be merged with the values of {@link BaseRequestOptions} before performing the request.
2) get(url: string, options?: RequestOptionsArgs): Observable ;
Performs a request with `get` http method.
3) post(url: string, body: any, options?: RequestOptionsArgs): Observable ;
Performs a request with `post` http method.
4) put(url: string, body: any, options?: RequestOptionsArgs): Observable ;
Performs a request with `put` http method.
5) delete(url: string, options?: RequestOptionsArgs): Observable ;
Performs a request with `delete` http method.
6) patch(url: string, body: any, options?: RequestOptionsArgs): Observable ;
Performs a request with `patch` http method.
7) head(url: string, options?: RequestOptionsArgs): Observable ;
Performs a request with `head` http method.
Note - Each method takes in a url and a payload and returns a generic observable response type. Most generic for CRUD operation are post, put, get, delete.
 Using Angular HttpClientModule instead of HttpModule
• As of Angular 4.3.x and above, HttpClientModule is available. It has updated API's with support for progress events, json deserialization by default, Interceptors and many other great features.
• Http is the older API and in the future HttpModule with its Http class will eventually be deprecated.
 Observable vs Promises
Observable Promises
Observables handle multiple values over time. Promises are only called once and will return a single value.
Observables are cancellable.
public ngOnDestroy(): void { this.subscription.unsubscribe(); }
Promises are not cancellable.
This is a RxJS API. This is a JavaScript class.
Observables can either be asynchronous or synchronous depending on the underlying implementation.
Promise is used for asynchronous computation.
Observable is a representation of any set of values over any amount of time.
A Promise represents value which may be available now, in the future or never.
Observable provides methods such as map(), catch() , forEach, reduce, retry(), or replay() etc. map() applies a function to each value emitted by source Observable and returns finally an instance of Observable.
Promise has methods such as then(), catch() etc. http.get() returns Observable and to convert it into Promise we need to call RxJS toPromise() on the instance of Observable.
catch() is called when an error is occurred. catch() also returns Observable.
The catch() method of Promise is executed when an error is occurred and it also returns Promise.
Example of Observable-

Step 2 − Define an interface which will be the class definition to store the information from our products.json file. Create a file called products.ts and insert the following code-

export interface IProduct { ProductID: number; ProductName: string; }

The above interface has the definition for the ProductID and ProductName as properties for the interface.
Step 3 − In the app.module.ts file include the following code –

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { HttpModule } from '@angular/http'; @NgModule ({ imports: [ BrowserModule,HttpModule], declarations: [ AppComponent], bootstrap: [ AppComponent ] }) export class AppModule { }

Step 4 − Define a product.service.ts file in Visual Studio code and insert the following code in the file.

import { Injectable } from '@angular/core'; import { Http , Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/do'; import { IProduct } from './product'; @Injectable() export class ProductService { private _producturl='app/products.json'; constructor(private _http: Http){} getproducts(): Observable { return this._http.get(this._producturl) .map((response: Response) => response.json()) .do(data => console.log(JSON.stringify(data))); } }

Note:-
• The import {Http, Response} from '@angular/http' statement is used to ensure that the http function can be used to get the data from the products.json file.
• The following statements are used to make use of the Reactive framework which can be used to create an Observable variable. The Observable framework is used to detect any changes in the http response which can then be sent back to the main application.

import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/do';

• The statement private _producturl = 'app/products.json' in the class is used to specify the location of our data source. It can also specify the location of web service if required.
• We define a variable of the type Http which will be used to get the response from the data source.
• Once we get the data from the data source, we then use the JSON.stringify(data) command to send the data to the console in the browser.
Step 5 − Now in the app.component.ts file, place the following code.

import { Component } from '@angular/core'; import { IProduct } from './product'; import { ProductService } from './products.service'; import { appService } from './app.service'; import { Http , Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; @Component ({ selector: 'my-app', template: '
Hello
', providers: [ProductService] }) export class AppComponent { iproducts: IProduct[]; constructor(private _product: ProductService) { } ngOnInit() : void { this._product.getproducts() .subscribe(iproducts => this.iproducts = iproducts); } }

Here, the main thing in the code is the subscribe option which is used to listen to the Observable getproducts() function to listen for data from the data source.
Step 6 − Now save all the codes and run the application using npm. Go to the browser, we will see the following output.
 HttpInterceptor in Angular
 The HttpInterceptor interface was released with Angular v4.3.
 It allows us to modify all incoming/outgoing HTTP requests in our Angular app.
 It is like a middleware function in Express or Spring Boot app.
 We can implement the HttpInterceptor interface to modify request headers, cache requests, log information, and more.
 It has been used to pre-process and post-process the HTTP request before sending and after getting response from the server.
 It is implemented globally for respective module.
 Angular HttpInterceptor provides intercept() method to intercept outgoing request before calling next interceptor. intercept() method accepts HttpRequest and HttpHandler as arguments.
 Interceptors can be used in two different phases in a life cycle of an HTTP request to a server-
1) Before making the request server:
This happens before the call is made to server. It can be used to change the request configuration of HTTP call. The most common use case for this is to add an Access Token to be sent to the server with each HTTP request so that it can be validated at server end.
2) After Getting the response from server:
This happens once we get the response from the server. It can be used to change the response before it is being passed to the code block from where HTTP call was made. The most common use case for this is to Handle Global Error Handling across the app.
 Need of HTTP Interceptors
• When our application makes a request, interceptors transform it before sending it to the server, and the interceptors can transform the response on its way back before your application sees it.
• In our application, we want a common place where we can check for all the request made to server from our application and check all the responses from the server, the best way is to use INTERCEPTORS.
 List of steps we need to do to implement the Interceptors in our Angular App
Step 1. Import the HttpClientModule into our application in app.
Step 2. Add a Class decorated with Injector Decorator, where we will write our logic for Interceptors.
Step 3. Then we provide information to angular to use our class from 2nd step as interceptors.
 Creation of interceptor in Angular-
To create interceptor, we need to create a service that will implement HttpInterceptor and define intercept() method.

We will create an interceptor for logging. We will log request method, request URL and request completion time with success or failure message.

logging-interceptor.ts import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http'; import { finalize, tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements HttpInterceptor { intercept(req: HttpRequest , next: HttpHandler) { const startTime = Date.now(); let status: string; return next.handle(req).pipe( tap( event => { status = ''; if (event instanceof HttpResponse) { status = 'succeeded'; } }, error => status = 'failed' ), finalize(() => { const elapsedTime = Date.now() - startTime; const message = req.method + " " + req.urlWithParams +" "+ status + " in " + elapsedTime + "ms"; this.logDetails(message); }) ); } private logDetails(msg: string) { console.log(msg); } }

• HttpRequest: It is an outgoing HTTP request. It provides getters to fetch request properties such as method, urlWithParams etc.
• HttpHandler: It transforms an HttpRequest into a stream of HttpEvent. It provides handle() method to dispatch request from first interceptor to second and so on.
• HttpResponse: It is a full HTTP response. It has getter methods such as body, headers, status, url etc.
• pipe(): It runs functional operators into a chain.
• tap(): It performs a side effect for every emission on the source Observable and returns Observable identical to the source, if there is no error.
• finalize(): It calls specified function when the source terminates on complete or error and returns Observable identical to the source.
• Configure Interceptor with Provider: Interceptors are configured with provider as following.

{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }

Note: As there can be more than one HTTP interceptor and we need to maintain its order, so it is better to create a const array as following.

export const httpInterceptorProviders = [ { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]; @NgModule({ providers: [ httpInterceptorProviders ], }) export class AppModule { } • Intercepts HttpRequest or HttpResponse and handles them. interface HttpInterceptor { intercept(req: HttpRequest , next: HttpHandler): Observable }

Description:

 Most interceptors transform the outgoing request before passing it to the next interceptor in the chain, by calling next.handle(transformedReq).
 An interceptor may transform the response event stream as well, by applying additional RxJS operators on the stream returned by next.handle().
 More rarely, an interceptor may handle the request entirely, and compose a new event stream instead of invoking next.handle(). This is an acceptable behavior, but in further interceptors will be skipped entirely.
 It is also rare but valid for an interceptor to return multiple responses on the event stream for a single request.
 Methods- intercept()

Syntax- intercept(req: HttpRequest , next: HttpHandler): Observable>

 Parameters
req HttpRequest
next HttpHandler
 Returns
Observable
Complete Example

logging-interceptor.ts import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http'; import { finalize, tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements HttpInterceptor { intercept(req: HttpRequest , next: HttpHandler) { const startTime = Date.now(); let status: string; return next.handle(req).pipe( tap( event => { status = ''; if (event instanceof HttpResponse) { status = 'succeeded'; } }, error => status = 'failed' ), finalize(() => { const elapsedTime = Date.now() - startTime; const message = req.method + " " + req.urlWithParams +" "+ status + " in " + elapsedTime + "ms"; this.logDetails(message); }) ); } private logDetails(msg: string) { console.log(msg); } } index.ts import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { LoggingInterceptor } from './logging-interceptor'; export const httpInterceptorProviders = [ { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]; book.ts export interface Book { id: number; name: string; category: string; year: string; } book.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Book } from './book'; @Injectable() export class BookService { constructor(private http: HttpClient) { } bookUrl = "/api/books"; getBooks(): Observable { return this.http.get (this.bookUrl); } } book.component.ts import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { BookService } from './book.service'; import { Book } from './book'; @Component({ selector: 'app-book', templateUrl: './book.component.html' }) export class BookComponent implements OnInit { books$: Observable constructor(private bookService: BookService) { } ngOnInit() { this.getBooks(); } getBooks() { this.books$ = this.bookService.getBooks(); } } book.component.html

Book Details

  • Id: {{book.id}}, Name: {{book.name}}, Category: {{book.category}}, Year: {{book.year}}
test-data.ts import { InMemoryDbService } from 'angular-in-memory-web-api'; export class TestData implements InMemoryDbService { createDb() { let bookDetails = [ { id: '101', name: 'Angular 2 by Krishna', category: 'Angular', year: '2015' }, { id: '102', name: 'AngularJS by Krishna', category: 'Angular', year: '2015' } ]; return { books: bookDetails }; } } app.component.ts import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` ` }) export class AppComponent { } app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { BookComponent } from './book.component'; import { BookService } from './book.service'; import { httpInterceptorProviders } from './http-interceptors/index'; //For InMemory testing import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { TestData } from './test-data'; @NgModule({ imports: [ BrowserModule, HttpClientModule, InMemoryWebApiModule.forRoot(TestData) ], declarations: [ AppComponent, BookComponent ], providers: [ BookService, httpInterceptorProviders ], bootstrap: [ AppComponent ] }) export class AppModule { }

Run Application-
1. Install Angular In-Memory Web API.
npm i angular-in-memory-web-api –save
2. Download source code using download link given below on this page.
3. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
4. Run ng serve using command prompt.
5. Access the URL http://localhost:4200
Find the output in console.
GET /api/books succeeded in 506ms