AngularJS 2.0 From The Beginning - Http Module Part One - Day Seventeen

I am here to continue the discussion around AngularJS 2.0. In my previous article, I already discussed about the model driven form binding in Angular 2.0. Now, in this article, we will discuss about http module or how to call external APIs in the Angular 2.0. In case, you did not have a look at the previous articles of this series, go through the links mentioned below.

Angular 2 introduces many innovative concepts like performance improvements,  Component Routing, sharpened Dependency Injection (DI), lazy loading, async templating, mobile development with Native Script; all linked with a solid tooling and excellent testing support. Making HTTP requests in Angular 2 apps looks somewhat different then what we're used to from Angular 1.x, a key difference being that Angular 2's Http returns observables.

It is very clear to us that Angular 2.0 always look and feels different  compared to Angular 1.x. In case of Http API calling, the same scenario occurred. The $http Service, which Angular 1.x provides us works very nicely in most of the cases. Angular 2.0 Http requires us to learn some new concept or mechanism, including how to work with observables.

Reactive Extensions for JavaScript (RxJS) is a reactive streams library, which allows you to work with Observables. RxJS combines ObservablesOperators and Schedulers, so we can subscribe to streams and react to changes, using composable operations.

Differences between Angular 1.x $http and Angular 2 Http

Angular 2's Http API calling again provides a fairly straightforward way of handling the requests. For starters, HTTP calls in Angular 2 by default return observables through RxJS, whereas $http in Angular 1.x returns Promises. Using observable streams, gives us the benefit of greater flexibility, when it comes to handling the responses coming from HTTP requests. For example, we have the potential of tapping into useful RxJS operators like retry, so that a failed HTTP request is automatically re-sent, which is useful for the cases, where the users have poor or intermittent network communication.

In Angular 2, Http is accessed as an injectable class from angular2/http and, just like other classes, we import it when we want to use it in our components. Angular 2 also comes with a set of injectable providers for Http, which are imported via HTTP_PROVIDERS. With these , we get the providers such as RequestOptions and ResponseOptions, which allows us to modify the requests and the responses by extending the base class for each. In Angular 1.x, we would do this by providing a transformRequest or transformResponse function to our $httpoptions.

Observables vs Promises

When used with Http, both implementations provide an easy API to handle the requests, but there are some key differences, which makes Observables; a superior alternative. 

  • Promises only accepts one value unless we compose multiple Promises (Eg: $q.all).
  • Promises can’t be cancelled.

Angular 2 http module @angular/http exposes a Http Service, which our Application can use to access the Web Services over HTTP. We’ll use this utility in our PeopleService Service. We start by importing it together will all the types involved in doing http request:

  1. import { Http, Response } from '@angular/http';  
  2. import { Observable } from 'rxjs/Rx';   

These are all the types and methods required to make and handle an HTTP request to a Web service:

  • Http
    The Angular 2 http service that provides the API to make HTTP requests with methods corresponding to HTTP verbs like get, post, put, etc
  • Observable
    which is the async pattern used in Angular 2. The concept of observable comes from the observer design pattern as an object that notifies an interested party of observers when something interesting happens. In RxJs it has been generalized to manage sequences of data or events, to become composable with other observables and to provide a lot of utility functions known as operators that let you achieve amazing stuff.

Angular comes with its own HTTP library, which we can use to call out to external APIs.

When we make calls to an external Server, we want our user to continue to be able to interact with the page i.e. we don’t want our page to freeze until the HTTP request returns from the external Server. To achieve this effect, our HTTP requests are asynchronous.

Dealing with an asynchronous code is, historically, more tricky than dealing with synchronous code. In Javascript, there are generally three approaches of dealing with asynchronous code, namely.

  1. Callbacks
  2. Promises
  3. Observables
Now in this article, we will demonstrate how to access or call GET method of a Web API controller to fetch the data.

For this, we first need to add another project of type ASP.NET Web Application and select Web API option from the new dialog box. After creating a project, add the files given below.
 
Model Class -- Employee.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5.   
  6. namespace SampleAPI.Models.Sample  
  7. {  
  8.     public class Employee  
  9.     {  
  10.         public int Id { get; set; }  
  11.         public string Code { get; set; }  
  12.         public string Name { get; set; }  
  13.         public DateTime DOB { get; set; }  
  14.         public DateTime DOJ { get; set; }  
  15.         public string Department { get; set; }  
  16.         public string Designation { get; set; }  
  17.         public double Salary { get; set; }  
  18.     }  
  19. }   
Web API Controller --  EmployeeController.cs
  1. using SampleAPI.Models.Sample;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Net;  
  6. using System.Net.Http;  
  7. using System.Web.Http;  
  8. using System.Web.Http.Description;  
  9.   
  10. namespace SampleAPI.Controllers.Sample  
  11. {  
  12.     public class EmployeeController : ApiController  
  13.     {  
  14.         public EmployeeController()  
  15.         {  
  16.                           
  17.         }  
  18.   
  19.         [ResponseType(typeof(Employee))]  
  20.         [HttpGet]  
  21.         [Route("Employee/GetEmployee")]  
  22.         public IHttpActionResult GetEmployee()  
  23.         {  
  24.             return Ok(this.FetchEmployee());  
  25.         }  
  26.   
  27.         private List<Employee> FetchEmployee()  
  28.         {  
  29.             List<Employee> lstData = new List<Employee>();  
  30.             Employee objEmp = new Employee() { };  
  31.             objEmp.Id = 1;  
  32.             objEmp.Code = "A001";  
  33.             objEmp.Name = "RABIN";  
  34.             objEmp.DOB = Convert.ToDateTime("10-06-1980");  
  35.             objEmp.DOJ = Convert.ToDateTime("01-09-2006");  
  36.             objEmp.Department = "ACCOUNTS";  
  37.             objEmp.Designation = "CLERK";  
  38.             objEmp.Salary = 15000.00;  
  39.             lstData.Add(objEmp);  
  40.   
  41.             objEmp = new Employee() { };  
  42.             objEmp.Id = 2;  
  43.             objEmp.Code = "A002";  
  44.             objEmp.Name = "SUJIT";  
  45.             objEmp.DOB = Convert.ToDateTime("12-22-1986");  
  46.             objEmp.DOJ = Convert.ToDateTime("04-15-2010");  
  47.             objEmp.Department = "SALES";  
  48.             objEmp.Designation = "MANAGER";  
  49.             objEmp.Salary = 35000.00;  
  50.             lstData.Add(objEmp);  
  51.   
  52.             objEmp = new Employee() { };  
  53.             objEmp.Id = 3;  
  54.             objEmp.Code = "A003";  
  55.             objEmp.Name = "KAMALESH";  
  56.             objEmp.DOB = Convert.ToDateTime("03-22-1982");  
  57.             objEmp.DOJ = Convert.ToDateTime("07-15-2006");  
  58.             objEmp.Department = "ACCOUNTS";  
  59.             objEmp.Designation = "CLERK";  
  60.             objEmp.Salary = 16000.00;  
  61.             lstData.Add(objEmp);  
  62.   
  63.             return lstData;  
  64.         }  
  65.   
  66.     }  

Now, we can run the API project and access the GetEmployee method from the Browser to fetch the data but when we want to access the same Web API method from our Angular 2 project, then an error will occur called cross origin error. To solve this error, we need to install Microsoft ASP.NET Cors in Web API project from NuGet Manager, as shown below.



Now, change WebAPIConfig.cs file of Web AP project, as shown below.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net.Http;  
  5. using System.Web.Http;  
  6. using Microsoft.Owin.Security.OAuth;  
  7. using Newtonsoft.Json.Serialization;  
  8. using System.Web.Http.Cors;  
  9.   
  10. namespace SampleAPI  
  11. {  
  12.     public static class WebApiConfig  
  13.     {  
  14.         public static void Register(HttpConfiguration config)  
  15.         {  
  16.             // Web API configuration and services  
  17.             // Configure Web API to use only bearer token authentication.  
  18.             config.SuppressDefaultHostAuthentication();  
  19.             config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));  
  20.   
  21.             // Web API routes  
  22.             config.MapHttpAttributeRoutes();  
  23.   
  24.             var cors = new EnableCorsAttribute("*", "*", "*");  
  25.             config.EnableCors(cors);  
  26.   
  27.             config.Routes.MapHttpRoute(  
  28.                 name: "DefaultApi",  
  29.                 routeTemplate: "api/{controller}/{id}",  
  30.                 defaults: new { id = RouteParameter.Optional }  
  31.             );  
  32.         }  
  33.     }  

Now, go back to Angular 2 project and create the files given below with the code.

app.component.homepage.html
  1. <div>  
  2.     <h3>HTTP Module Sample - Get Data</h3>  
  3.     <div class="panel panel-default">  
  4.         <div class="panel-body">  
  5.             <table class="table table-striped table-bordered">  
  6.                 <thead>  
  7.                     <tr>  
  8.                         <th>Srl No</th>  
  9.                         <th>Alias</th>  
  10.                         <th>Employee Name</th>  
  11.                         <th>Date of Birth</th>  
  12.                         <th>Join Date</th>  
  13.                         <th>Department</th>  
  14.                         <th>Designation</th>  
  15.                         <th>Salary</th>  
  16.                     </tr>  
  17.                 </thead>  
  18.                 <tbody>  
  19.                     <tr *ngFor="let item of data">  
  20.                         <td>{{item.Id}}</td>  
  21.                         <td>{{item.Code}}</td>  
  22.                         <td>{{item.Name}}</td>  
  23.                         <td>{{item.DOB | date :'shortDate'}}</td>  
  24.                         <td>{{item.DOJ | date :'mediumDate'}}</td>  
  25.                         <td>{{item.Department}}</td>  
  26.                         <td>{{item.Designation}}</td>  
  27.                         <td>{{item.Salary |currency:'INR':true}}</td>  
  28.                     </tr>  
  29.                 </tbody>  
  30.             </table>  
  31.             <p>  
  32.                 <button class="btn btn-primary" (click)="loadData()">  
  33.                     Load Data  
  34.                 </button>  
  35.             </p>  
  36.         </div>  
  37.     </div>  
  38. </div> 
app.component.homepage.ts
  1. import { Component, OnInit, ViewChild } from '@angular/core';  
  2. import { Http, Response } from '@angular/http';  
  3. import 'rxjs/Rx';  
  4.   
  5. @Component({  
  6.     moduleId: module.id,  
  7.     selector: 'home-page',  
  8.     templateUrl: 'app.component.homepage.html'  
  9. })  
  10.   
  11. export class HomePageComponent implements OnInit {  
  12.   
  13.     private data: Array<any> = [];  
  14.   
  15.     constructor(private http: Http) {  
  16.     }  
  17.   
  18.     ngOnInit(): void {  
  19.     }  
  20.   
  21.     private loadData(): void {  
  22.         debugger;  
  23.         let self = this;         
  24.         this.http.request('http://localhost:5201/employee/getemployee')  
  25.             .subscribe((res: Response) => {  
  26.                 self.data = res.json();  
  27.             });  
  28.     }  
  29.   

app.module.ts
  1. import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3. import { ReactiveFormsModule } from "@angular/forms";  
  4. import { HttpModule } from '@angular/http';  
  5.   
  6. import { HomePageComponent } from './src/app.component.homepage';  
  7.   
  8. @NgModule({  
  9.     imports: [BrowserModule, ReactiveFormsModule, HttpModule],  
  10.     declarations: [HomePageComponent],  
  11.     bootstrap: [HomePageComponent]  
  12. })  
  13. export class AppModule { } 
main.ts
  1. import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';  
  2.   
  3. import { AppModule } from './app.module';  
  4.   
  5. const platform = platformBrowserDynamic();  
  6. platform.bootstrapModule(AppModule); 
index.html
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title>Angular2 - HTTP Module (GET) </title>  
  5.     <meta charset="UTF-8">  
  6.     <meta name="viewport" content="width=device-width, initial-scale=1">  
  7.     <link href="../resources/style/bootstrap.css" rel="stylesheet" />  
  8.     <link href="../resources/style/style1.css" rel="stylesheet" />  
  9.     <!-- Polyfill(s) for older browsers -->  
  10.     <script src="../resources/js/jquery-2.1.1.js"></script>  
  11.     <script src="../resources/js/bootstrap.js"></script>  
  12.   
  13.     <script src="../node_modules/core-js/client/shim.min.js"></script>  
  14.     <script src="../node_modules/zone.js/dist/zone.js"></script>  
  15.     <script src="../node_modules/reflect-metadata/Reflect.js"></script>  
  16.     <script src="../node_modules/systemjs/dist/system.src.js"></script>  
  17.     <script src="../systemjs.config.js"></script>  
  18.     <script>  
  19.         System.import('app').catch(function (err) { console.error(err); });  
  20.     </script>  
  21.     <!-- Set the base href, demo only! In your app: <base href="/"> -->  
  22.     <script>document.write('<base href="' + document.location + '" />');</script>  
  23. </head>  
  24. <body>  
  25.     <home-page>Loading</home-page>  
  26. </body>  
  27. </html> 
Now, run the code and the output is shown below.