Blogger news

Blogger templates

Monday, July 21, 2014

Consuming a REST Service with AngularJS using $http and $q services

If you are new to AngularJS I would prefer to go through my introduction blog on AngularJS before read this article.

There are two ways we can call REST service from AngularJS,
1. Using $http service 
2. Using $resource service

In this article I am focusing on $http service but I promise that will write another article on $resource service as well.
According to official AngularJS documentation 
"The $http service is a core Angular service that facilitates communication with the remote HTTP servers via the browser's XMLHttpRequest object or via JSONP"Most of the real time $http service is based on deferred/promise (I will explain in later in this article) exposed by $q service but for simple $http call you don't need $q service. I will explain both approach here. Enough of theory let's switch to our sample application and I will explain parts by parts.
First let's start with simple $http service without $q service.
As usual let's start with creating module (I assume you have already ready my previous articles).

Step 1 - Creating module
var RestServiceModule = angular.module('RestServiceModule', []);

Step 2- Creating Controller

If you are not familiar with controllers I suggest my blog on Controllers in AngularJS
RestServiceModule.controller('RestServiceController', function ($scope, RestServiceFactory) {
  
    RestServiceFactory.GetEnvironmentDetails(function (environmentDetails) {
        $scope.EnvironmentDetails = environmentDetails;
    });


});

As you can see in controller we inject a service/factory object and call 'GetEnvironmentDetais' method of 'RestServiceFactory'. 'GetEnvironmentDetais' functions has one parameter which is a callback function(Hope you have better understanding about callbacks in JavaScript else read some good article about that) and which will call asynchronously with data when the request is success. Once callback execute we will assign 'environmentDetails' which is nothing but the real data to $scope.EnvironmentDetails.

so obviously our next step would be to create service. If you are not familiar with creating custom service in AngularJS please read in article on Services in AngularJS 

Step 3 - Creating Service

RestServiceModule.factory('RestServiceFactory'function ($http) {
    return {
 GetEnvironmentDetails: function (successCallBack) {           
 $http({ method: 'GET',url: '../api/environmentdetails/GetEnvironmentDetails' }).
     success(function (data, status, headers, config) {
//This call back method will call asynchronously when data is available
         return successCallBack(data);
     }).
     error(function (data, status, headers, config) {
//This call back method will call asynchronously if an error occurs
//or server returns response with an error status code

         alert("Error in calling service " + status);
     });
        }
    };
});

So as you seen here we inject $http service which is an AngularJS built in service. The $http service is a function which takes a single argument , an object with configuration information included verb (GET,POST,PUT,DELETE etc) and url that is used to generate an HTTP request and returns a promise with two $http specific methods: success and error. In our example url is the url of the REST service which we will create in next step. According to request status success or error method will call asynchronously. Once success call then call our callback method with the real data that we got from REST service.

Explanation of parameters of success and error method is below,
data – The response body transformed with the transform functions.
status – HTTP status code of the response.
headers –  Header getter function.

config –  The configuration object that was used to generate the request.

Step 4 - Creating REST Service
I am creating REST service with Asp.net Web API but you can use any other framework or manually to create REST service. I am not going in depth about REST service. I am sure you will get 100's of good articles about that. Anyway REST service method I created is below,


        [HttpGet]
        public EnviromentDetails GetEnvironmentDetails()
        {
            return new EnviromentDetails
                                   {
          EnvironmentName ="TestServer", EnvironmentIP ="100.2.3.4.5"
                                    };

        }

So our REST service method is returning an object of 'EnvironmentDetails' and Asp.Net Web API automatically convert it to JSON.Step 4 - Create and bind result to View
Our final step to create and bind result to our html.

<!DOCTYPE html>
<html ng-app="RestServiceModule">
<head>
    <title></title>
</head>
<body ng-controller="RestServiceController">
    <div><h3>Environment Name:-</h3>
        {{EnvironmentDetails.EnvironmentName}}
    </div>
    <div>
        <h3>Environment IP:-</h3>
        {{EnvironmentDetails.EnvironmentIP}}
    </div>
    <script src="Scripts/AngularJS/angular.min.js"></script>
    <script src="Scripts/Module/RestServiceModule.js"></script>
    <script src="Factories/RestServiceFactory.js"></script>
    <script src="Scripts/Controllers/RestController.js"></script>
</body>
</html> 


As you know we have specified Module and Controller in the view. As I told before from REST service controller will receive a JSON object 'EnvironmentDetails' which has two properties EnvironmentName and EnvironmentIP.  Output will looks like below



Cool you are done with your simple $http call to REST service.

Next let's see where and how $q service fits with $http service call. First I am going to modify the service that I created before

RestServiceModule.factory('RestServiceFactory', function ($http, $q) {
    return {
        GetEnvironmentDetails: function () {

            var deferred = $q.defer();

            $http({ method: 'GET', url: '../api/environmentdetails/GetEnvironmentDetails' }).
     success(function (data, status, headers, config) {
            deferred.resolve(data);
                }).
     error(function (data, status, headers, config) {
         deferred.reject(status);
     });
            return deferred.promise;
        }

    };
});

When you compare with previous service we created there are few changes. which are below,


a. We injected '$q' service
b.  We have removed the callback method ''successCallBack"
c. Instead of calling 
''successCallBack" function after success we added "deferred.resolve(data)"
d. We are returning "deferred.promise"

What is all these? Well I will explain it

The idea of promise library is they provide a way to work with asynchronous calls and what they do is immediately synchronously return you a promise. That promise is an object that usually has a method on it like 'then'and when the promise is fulfilled it will call that function. It is a way to avoid passing callback back and forth. It has two parts, deferred API and promise API.


a. The deferred API
As you have seen new instance of deferred is constructed by calling $q.defer().

The purpose of the deferred object is to expose the associated Promise instance as well as APIs that can be used for signaling the successful or unsuccessful completion, as well as the status of the task.
Deferred API has below methods,
resolve(value) – resolves the derived promise with the value. 
reject(reason) – rejects the derived promise with the reason. 

notify(value) - provides updates on the status of the promise's execution.

resolve and reject you have already seen in our modified 'RestServiceFactory' service.


Before explaining promise API I have to modify our 'RestServiceController'

RestServiceModule.controller('RestServiceController', function ($scope, RestServiceFactory) {
  
    RestServiceFactory.GetEnvironmentDetails().then(
        function (environmentDetails) { $scope.EnvironmentDetails = environmentDetails; },
        function (statuscode) { alert("Error calling service " + statuscode);}
        );

});

So what's change here when compare to previous controller? Yes you are right we have removed callback function and calling 'then' method of the promise API. Now let's see what is promise API.
b. The promise API

A new promise instance is created when a deferred instance is created and can be retrieved by calling deferred.promise.


The purpose of the promise object is to allow for interested parties to get access to the result of the deferred task when it completes.

If you look our controller the method 'then' has two parameters (Callbacks). First callback will call for success and second will call for error. 


Other components in our first example will remain the same. Well that's pretty much about $http and $q service together.

No comments:

Post a Comment