This chapter mainly focuses on how AngularJS communicates with server-side code, such as web APIs, web services, or Data Access Layer (DAL). In this chapter, we will discuss how to retrieve data from the server using $http
and $resources
. This chapter also talks about the authentication and security of an AngularJS application.
This chapter is organized as follows:
$http
:GET
POST
HEAD
DELETE
PUT
JSONP
PATCH
A web application is the communication between a client and server made using the HTTP protocol where the server is responsible for serving web pages. The client, which is a web browser, requests a web page from the server, receives the server's response, and displays the response to the user. The user uses the client (web browser) to display web pages, watch videos online, and so on. Client-side programming and server-side programming refers to the programming that runs on a specific side of the server or client.
The following are the steps involved in client-server communication:
There are two different types of renderings: server side and client side. In server-side rendering, the client (browser) fetches web pages from a server over HTTP. In client-side rendering, JavaScript running on the client (browser) produces or manipulates the DOM. All browsers understand JavaScript and because of this, client-side rendering can be accomplished using JavaScript without sending a request to the server and waiting for its response. The advantage of client-side rendering is that the user can update a web page instantly. When the user clicks on any button, the click event updates the information on the page rather than waiting for a few hundred milliseconds to get a response from the server in order to display the page on the client side.
Best practice to render web applications is to render the initial state of the web page on the server and interactive widgets and then to re-render the part of the web page that needs to be updated on the client side. It is typical to render the meat of the page on the server side and then to enhance the page on the client side with a client library using jQuery or the AngularJS framework.
Server-side programming and client-side programming cannot be combined together because typically, server-side and client-side programming are performed in different programming languages. Server-side programming is the program that generally runs on the server and interacts with the resource management tools, such as SQL, Oracle databases, and so on. For server-side programming, we can use any server-side programming language, such as C#, Visual Basic .Net, C++, Java, and so on.
Client-side programming can be achieved using a client programming library or framework, such as jQuery, AngularJS Backbone, and so on. All client-side libraries and frameworks are based on JavaScript. The client-side program runs on the client. The following figure shows the communication between different clients and the server:
The preceding figure shows how different clients (browsers) send requests to a web server and receive a response using the HTTP protocol.
These days, fetching data from a server is different from when Active Server Pages (ASP) and Java Server Pages (JSP) were developed. Asynchronous JavaScript and XML (Ajax) enables communication with the backend code without refreshing a web page. Ajax is a combination of different web development techniques to develop asynchronous client-side web applications. Using Ajax, data can be retrieved and sent to the server without interfering with the display of the DOM of the existing web page.
AngularJS is one of the really popular frameworks for client-side rendering. AngularJS allows you to extend HTML to create templates and enable a view and model for one-way or two-way data binding. In the real world, an application depends on the server-side code, which is known as backend, to execute the core business logic and communicate with the database. The AngularJS framework provides built-in support to communicate with a server. Data can be fetched either using an XMLHttpRequest
object or JSON; in case of JSON, the request does not need to be asynchronous.
To make an Ajax request to the server, XMLHttpRequest
makes a request, receives the server's response, checks for errors, and processes the server's response. This is a great deal of work for a simple, common, and frequently repeated task. The AngularJS API uses a promise interface; a promise symbolizes the final result of an operation. We can use a promise API to specify what to do when an operation finally succeeds or fails. The promise API is an established technique for server-side communication. In this technique, all requests made to a server are nonblocking or asynchronous requests, which means that, the response from the server will return some time in the near future. The promise interface makes sure that the response from the server is handled according to when it arrives from the server. In AngularJS, there are three functions then, success, and error that are used to handle the response from the server.
For example, we want to retrieve a car's information from the server. The web API that will be discussed in Chapter 5, Creating Applications Using AngularJS, Entity Framework, and ASP.NET Web API, is available at /Cars/getCarInfo
and is required by the model as a parameter. The request from the client to fetch the car information from the server using AngularJS $http
will look like the following:
app.controller('ctrlGetCarInfo', function ($scope, $http) { var Url = '/Cars/getCarInfo'; $http.get(Url, {params:{model:'Toyota'} }).success(function(data, status, headers, config) { <!--Do something when it is successful --> }).error(function(data, status, headers, config) { <! - - Handle the error - -> }); });
In the preceding code example, the client makes an Ajax request to the server in order to find out whether the car model used is Toyota
. This request will not wait for the response from the server. Whenever, in the near future, the response is received from the server, the promise interface calls the appropriate function, success or error, depending on the server's response.
There are two different ways to implement $http
in AngularJS. The first implementation is shown in the preceding code and the second approach is as follows:
app.controller('ctrlGetCarInfo', function ($scope, $http) { var Url = '/Cars/getCarInfo'; $http({ method: 'GET', url: Url, params:{model:'Toyota'} }).success(function (data, status, headers, config) { <!--Do something when it is successful --> }).error(function (data, status, headers, config) { <! - - Handle the error - -> }); });
There is no difference between the previous two approaches in terms of output. The difference between the preceding two approaches is that in the first approach, we used $http.get()
and passed the parameters, such as Url
and params
, and this approach is known as a shortcut approach. In the second approach, we used $http
and passed get
as a parameter to the GET
method instead of using $http.get()
. It is a personal choice to use any approach. Personally, I prefer the second approach; we will use this approach for the rest of the chapter.
The $.ajax()
method in the jQuery library and $http.get()
in the AngularJS framework look almost the same. However, the implementation of these methods in both jQuery and AngularJS is different. jQuery uses its deferred library while AngularJS uses its $digest
integrated version of the q
library.
In AngularJS' promise API, success and error are special functions added to $http
. In both of the preceding examples of retrieving data from the server with $http
, we did not use the then
function of $http
. With promise, we can also use the then
function, which will take the then
function as the first parameter, and the error
function, which will be the second parameter of $http
, instead of using the success
function as the first and the error
function as the second parameter. The following code example demonstrates the use of the then
function of $http
:
app.controller('ctrlGetCarInfo', function ($scope, $http) { var Url = '/Cars/getCarInfo'; $http({ method: 'GET', url: Url, params:{model:'Toyota'} }).then(function (result) { Var list = result.data; }).error(function (data, status, headers, config) { <! - - Handle the error - -> }); });
In the preceding code, we replaced the .success
function with the .then
function. In this case, when we are using the .then
function, it returns a new promise that will unwrap and normalize the AngularJS API response. However, while using the .success
function, a new promise will not be returned; it will only return the original $http
promise.
AngularJS' built-in $http
service is good enough to serve most purposes. AngularJS' built-in $http
has the following methods:
$http.get(url, [config])
: This is used to get data from the server where:$http.head(url, [config])
: This is used to get the full header information of the request where:url
: This is the absolute or relative URL path of destination request (required)config
: This is the configuration object (optional)$http.post(url, data, [config])
: This is used to post data to server where:$http.put(url, data, [config])
url
: This is the absolute or relative URL path of destination request (required)data
: This is the data needs to post to the server (required)config
: This is the configuration object (optional)$http.delete(url, [config])
: This is used to delete data from the server where:url
: This is the absolute or relative URL path of destination request (required)config
: This is the configuration object (optional)$http.jsonp(url, [config])
: This is used to get JSON data from the server of a different domain where:url
: This is the absolute or relative URL path of destination request (required)config
: This is the configuration object (optional)$http.patch(url, data, [config])
url
: This is the absolute or relative URL path of destination request (required)data
: This is the data needs to post to the server (required)config
: This is the configuration object (optional)We can customize the default $http
configuration, such as to set the customer header, transform the client request and server response, set timeout instead of default timeout, enable cache and/or set the response type, and so on.
The following table shows the request arguments and their description for which we can use $http
:
The following table shows the response object properties:
Name |
Description |
---|---|
|
This object return string, the transform function with response body |
| |
| |
| |
|
The following code shows how to implement custom configuration for $http
. In the following example, we will use the post
method of $http
to post data on the server. If we want to post the data using the post
method of $http
, the content type needs to be changed to application/x-www-form-urlencoded
. Instead of using the default content type in the header, we can change the content type in the header by changing the default configuration of $http
as shown in the following code:
app.controller('ctrlSetCarInfo', function ($scope, $http) { var Url = '/Cars/setCarInfo'; var newConfig = { timeout : 200, headers: {'Content-Type': 'application/x-www-form-urlencoded'} } $http({ method: 'POST', url: Url, data:{'data':data} }).success(function (data, status, headers, config) { <!--Do something when it is successful --> }).error(function (data, status, headers, config) { <! - - Handle the error - -> }); });
In the preceding code example, we posted the data on the server using the $http
service. Instead of using the built-in post
method of $http
, we customized the configuration. As you can see in the preceding code, we created a var newConfig
variable and assigned timeout: 200
and headers: {content type: 'application/x-www-form-urlencoded'}
. With this custom configuration, the timeout will occur after 200 milliseconds. The header of the request contains the content type of application/x-www-form-urlencoded
. In a similar way, we can implement AngularJS' built-in $http
methods.
In client-side application development, we are able to communicate with the server via the web API and populate the template (DOM) with data from the server's response. However, performance of the application is constantly affected if we get the data from the server, on each client's request, instead of caching the data. A cache is a constituent that stores the data on a client so that in future, the same client's request is served from the client cache instead of going back to server and receiving data from the server. The more a client's request is served from the cache, there is an increase in the overall application performance. Caching works with a key and a value combination; there is a key that will point to the data that is cached. When the data is requested from the client, the client first tries to find the data in the cache. If the assigned key is found in the cache, the client gets the data from the cache, which is known as a cache hit. Otherwise, if the data is not found in the cache, it is known as a cache miss and the client will request the data from the server.
In the AngularJS framework, the $http
service has a built-in cache option that by default is turned off. When the cache option is off, the response from the server is not stored in the cache. However, what if we want to cache data for each request for the same resource? To do this, we need to set the $http
request configuration property cache to true in order to use the default cache. The advantage of turning the cache option on for the $http
service is that it will enable the $http
service to prevent repeated requests to the server. When the $http
cache property is true
, the server response is stored in the cache. The next time the same request is made, the response is served from the cache instead of sending a request to the server. It is notable that even though the response is served from the cache, the delivery of the data will still be asynchronous.
If the client makes multiple GET
requests for the same resource, only the first request gets the data from the server and is stored in the client cache. The following requests will fetch the data from the cache, which will contain the same data as the first request.
The following code shows how to set the $http configuration property cache to true:
app.controller('ctrlGetCarInfo', function ($scope, $http) { var Url = '/Cars/getCarInfo'; $http({ method: 'GET', url: Url, cache:true, params:{model:'Toyota'} }).success(function (data, status, headers, config) { <!--Do something when it is successful --> }).error(function (data, status, headers, config) { <! - - Handle the error - -> }); }); <!—OR --> app.controller('ctrlGetCarInfo', function ($scope, $http) { var Url = '/Cars/getCarInfo'; $http.get(Url, {params:{model:'Toyota'}, cache:true }).success(function(data, status, headers, config) { <!--Do something when it is successful --> }).error(function(data, status, headers, config) { <! - - Handle the error - -> }); });
In the preceding code, we demonstrated how to set the client cache for server-side content using the $http
caching mechanism.
When we make a request to or receive a response from the server, the $http
service allows us to define transformation functions in the $http
configuration property for both the request and response. However, these options are optional; by default, the $http
service is set to handle JSON. JSON is a very malleable data format. It can contain randomly nested data structures.
In the AngularJS framework, when we are posting data using the $http
service, by default, the data will be serialized with JSON and sent to the server with the content type of application/json
. However, if we want to post data with a different content type, we can override the default $http
service transformation. Both the $http
request and response can be transformed using the $http
service's transform functions, transformRequest
and transformResponse
. These $http
configuration properties are single functions that return the transformed data or an array of such transformation functions, which allows us to make a new transformation in the transformation chain.
The default transformation of request and response of $http
is as follows:
Both the request and response transformation can be achieved within the $http
configuration property, which has access to the request and response header collection and nonserialized data. The purpose of the transformation is to update the header information and to return the updated data that will be injected in the underlying XMLHttpRequest
object.
If you want to update the default transformation of a single request and response, then provide the transformRequest
and/or transformResponse
properties of the configuration object passed into $http
, as shown in the following code:
function appendTransform(defaults, transform) { <!-- We can't guarantee that the default transformation is an array --> defaults = angular.isArray(defaults) ? defaults : [defaults]; <!--Append the new transformation to the defaults return --> defaults.concat(transform); } var Url = '/Cars/getCarInfo'; $http({ url: Url, method: 'GET', transformResponse:appendTransform($http.defaults.transformResponse, function(value) { return doTransform(value); }) });
If you have to update the default transformation of a whole application, best practice is to make a change to transformRequest
and/or transformResponse
in the application configuration instead of changing each request, as shown in the following code:
var app = angular.model('myApp',[]); app.config(['$httpProvider', function($httpProvider) { $httpProvider.defaults.transformResponse = function(data) { return performSomeTransformation(data); }; }])
In the preceding code, we updated the application's global configuration for transformation instead of updating the transformation for each request and/or response of $http
.