In Lesson 4 we wrapped up our device management CRUD in angularjs with both unit tests and end to end tests. We also organized our project structure with angularjs seed. So far, we have been using static data stored in an array within our Devices Service. In this lesson we will create a REST based Node/MongoDB backend which can persist our data.
Here are the stories we will work in Part-1 (Mongo integration will be Part-2):
Here are the stories we will work in Part-1 (Mongo integration will be Part-2):
- Create an node-express server application which will return the list of devices in JSON format (Read)
- Server returns a single device info given an ID
- Server updates devices information
- Server deletes a particular device
- Modify the angularjs application Service module to communicate with the server
Create an node-express server application which will return the list of devices in JSON format (Read) & which returns a single device information
- cd ~/angular/cotd
- mkdir server
- Create a file called package.json in the server folder to define our dependencies
{
"name": "cotd-server",
"description": "cotd backend",
"version": "0.0.1",
"private": "true",
"dependencies": {
"express": "3.2.2"
}
}
- npm install -- this will install express in the node_modules directory
Lets create the server application using node & express. We will create a GET route which will return a list of devices.
Code for server.js which returns a list of devices:
Run using node server.js; Test by going to localhost:3000/devices
Lets refactor our server code into node modules, which will help us later as the project becomes more complex. Create a sub-folder called routes & a new file called devices.js
Code for module devices.js
Refactored server.js
Add Device
We add a device using the POST method to send the JSON data. Add the following route to server:
In Server.js add:
app.configure(function () {
app.use(express.bodyParser());
});
app.post('/devices', devices.add); // add new device
In the devices module (devices.js):
exports.add = function(req,res){
var dev = req.body;
devices.push(dev);
console.log(devices);
res.send([{status: '1'}]);
};
You can test this using curl in the terminal or by using a chrome extension called POSTMAN:
curl -i -X POST -H 'Contet-Type: application/json' -d '{"id":7, "name": "iphone", "assetTag":"a23456", "owner":"dev", "desc":"iOS4.2"}' http://localhost:3000/devices
Implement update & deletion of a particular device
Deleting should be simple to achieve. It involves removing the JSON object from our devices array. Using the javascript array's filter api is fairly easy & straightforward. (Note: the filter is newer ecma standard and is not supported ie-8 and below, although the API document provides a work-around if you need it)
server.js - add delete route
app.delete('/devices/:id', devices.delete); // delete
server.js - add delete route
app.delete('/devices/:id', devices.delete); // delete
devices.js -- node module
exports.delete = function(req, res){
var id = req.params.id;
devices = devices.filter(function(item){
return item.id != id;
});
console.log("DELETED \n");
console.log(devices);
res.send([{status: '1'}]);
};
TEST: curl -i -X DELETE -H 'Conent-Type: application/json' http://localhost:3000/devices/6
Updating is also fairly straightforward to achieve in a similar manner, add the following in server.js
app.put('/devices/:id', devices.update); // update
devices.js
exports.update = function(req, res){
// get the device
var id = req.params.id;
var dev = req.body;
if(id != dev.id){
console.log("id's do not match for update");
res.send([{status: '0'}]);
}
console.log(dev);
// find the selected device & update
devices.forEach(function(item, i){
if(item.id == id){
// update
devices[i] = dev;
res.send([{status: '1'}]);
return;
}
});
res.send([{status: '0'}]);
};
TEST: curl -i -XPUT -H 'Content-Type: application/json' -d '{"id":6, "name": "testupdateiphone", "assetTag":"a23456", "owner":"dev", "desc":"iOS4.2"}' http://localhost:3000/devices/6
Lets check how we are doing with our stories: (git checkout v1.4.1)
Lets check how we are doing with our stories: (git checkout v1.4.1)
- DONE - Create an node-express server application which will return the list of devices in JSON format (Read)
- DONE - Server returns a single device info given an ID
- DONE - Server updates devices information
- DONE - Server deletes a particular device
- Modify the angularjs application Service module to communicate with the server
- Modify the unit & e2e test cases to use Mock data
Modify the angularjs application Service module to communicate with the server using $http & $ngResource
Angularjs provides the $http service which provides a pretty comprehensive API to handle HTTP requests. More info can be found here. Lets modify our angular app service to get the data from the express backend server we created above.
Add this to app/service.js file. This just makes the HTTP call for now.
items.query = function(){
var promise = $http.get('http://localhost:3000/devices')
.success(function(d){
console.log(d);
})
.error(function(d, status){
console.log("error getting data from server: " + status);
});
}
We will get the following common error on certain strict browsers like chrome:
To make our client side app be able to call the backend REST server the CORS header must be present which will tell the browser that this request is in good order. http://enable-cors.org/index.html
The following HTTP header needs to be added by the server to its response.
Access-Control-Allow-Origin: *
CORS References:
http://www.html5rocks.com/en/tutorials/cors/
http://stackoverflow.com/questions/7067966/how-to-allow-cors-in-express-nodejs
We will be using the node-cors package which will allow us to configure and handle the CORS header in our express server application. node-CORS is a node.js package for providing a connect/express middleware that can be used to enable CORS with various options.
Add the following in server/package.json:
"dependencies": {
"express": "3.2.2",
"cors": "*"
}
Modify the server to utilize cors package (server.js):
var express = require('express'),
cors = require('cors'),
devices = require('./routes/devices.js');
var app = express();
app.configure(function () {
app.use(express.bodyParser());
app.use(cors());
});
Lets modify the query method in our service to utilize deferred promises to get data from the backend. Here is the code which does that:
items.query = function(){
var deferred = $q.defer();
var url = "http://localhost:3000/devices";
$http.get(url).success(function(data, status){
deferred.resolve(data);
})
.error(function(data, status){
console.log("error getting data from server: " + status);
deferred.reject(data);
});
return deferred.promise;
}
Test it using http://localhost:8000/app/index.html#/ & the device list should be working at this point.
ngResource API documentation provides details around the usage of this angular service. To use this we need to include the angular-resource.js within our app.
index.html (add the following)
script src="lib/angular/angular-resource.js"
This resource definition gives the ability to interact with the RESTful server-side data source.
Within the controllers, you can call either the Devices "class" methods or the "instance" methods. The structure is typically:
Resource.query({params}, function success(){}, function error(){});
Refactored controller code is shown below, which performs all the CRUD operations:
--
--
Minor refactoring on the node server is shown here:
server.js
//Devices CRUD
app.get('/devices', devices.findAll); // list
app.get('/devices/:id', devices.findById); // find
app.post('/devices', devices.add); // add new device
app.put('/devices/:id', devices.update); // update
app.delete('/devices/:id', devices.delete); // delete
devices.js (module)
--
--
Add this to app/service.js file. This just makes the HTTP call for now.
items.query = function(){
var promise = $http.get('http://localhost:3000/devices')
.success(function(d){
console.log(d);
})
.error(function(d, status){
console.log("error getting data from server: " + status);
});
}
We will get the following common error on certain strict browsers like chrome:
CORS Background
This is because for security browsers do not allow request to a different domain, even though it is the same domain but a different port. The browsers are enforcing the same origin policy. CORS (Cross Origin Resource Sharing) "The CORS standard works by adding new HTTP headers that allow servers to serve resources to permitted origin domains." There are many options to handle same origin policy & CORS is one way to do it. The other is to configure a reverse proxy.To make our client side app be able to call the backend REST server the CORS header must be present which will tell the browser that this request is in good order. http://enable-cors.org/index.html
The following HTTP header needs to be added by the server to its response.
Access-Control-Allow-Origin: *
CORS References:
http://www.html5rocks.com/en/tutorials/cors/
http://stackoverflow.com/questions/7067966/how-to-allow-cors-in-express-nodejs
We will be using the node-cors package which will allow us to configure and handle the CORS header in our express server application. node-CORS is a node.js package for providing a connect/express middleware that can be used to enable CORS with various options.
Add the following in server/package.json:
"dependencies": {
"express": "3.2.2",
"cors": "*"
}
Modify the server to utilize cors package (server.js):
var express = require('express'),
cors = require('cors'),
devices = require('./routes/devices.js');
var app = express();
app.configure(function () {
app.use(express.bodyParser());
app.use(cors());
});
Lets modify the query method in our service to utilize deferred promises to get data from the backend. Here is the code which does that:
items.query = function(){
var deferred = $q.defer();
var url = "http://localhost:3000/devices";
$http.get(url).success(function(data, status){
deferred.resolve(data);
})
.error(function(data, status){
console.log("error getting data from server: " + status);
deferred.reject(data);
});
return deferred.promise;
}
Test it using http://localhost:8000/app/index.html#/ & the device list should be working at this point.
Using ngResource ($resource)
Instead of utilizing the lower level $http service, angular provides the $resource abstraction for interacting with JSON REST services. Lets use that to see how it helps alleviate all the boilerplate code we have to write if we have to use the lower level $http service.
ngResource API documentation provides details around the usage of this angular service. To use this we need to include the angular-resource.js within our app.
index.html (add the following)
script src="lib/angular/angular-resource.js"
app.js (add to include the dependency)
angular.module('cotd', ['cotd.filters', 'cotd.services',
'cotd.directives', 'cotd.controllers', 'ngResource']).
Using ngResource simplifies our service module significantly, since it provides a wrapper around the common REST functionality. Query, Save, Delete & Update functionalities are provided out of the box. We can replace all our previous code with 3 lines like so:
services.js (modify to include $resource)
.factory('Devices', ['$resource', function($resource){
return $resource('http://localhost\\:3000/devices/:deviceId',
{},
{update: {method:'PUT'}, isArray:false}
);
}]);
Using ngResource simplifies our service module significantly, since it provides a wrapper around the common REST functionality. Query, Save, Delete & Update functionalities are provided out of the box. We can replace all our previous code with 3 lines like so:
services.js (modify to include $resource)
.factory('Devices', ['$resource', function($resource){
return $resource('http://localhost\\:3000/devices/:deviceId',
{},
{update: {method:'PUT'}, isArray:false}
);
}]);
This resource definition gives the ability to interact with the RESTful server-side data source.
Within the controllers, you can call either the Devices "class" methods or the "instance" methods. The structure is typically:
Resource.query({params}, function success(){}, function error(){});
Refactored controller code is shown below, which performs all the CRUD operations:
--
--
Minor refactoring on the node server is shown here:
server.js
//Devices CRUD
app.get('/devices', devices.findAll); // list
app.get('/devices/:id', devices.findById); // find
app.post('/devices', devices.add); // add new device
app.put('/devices/:id', devices.update); // update
app.delete('/devices/:id', devices.delete); // delete
devices.js (module)
--
--
git checkout v1.5.0
2 comments:
Music expresses that which cannot be said and on which it is impossible to be silent. See the link below for more info.
#expresses
www.ufgop.org
Today's Best article. It really helps me to enhance my skills.
AWS Training in Chennai
DevOps Training in Chennai
Java Training in Chennai
AngularJS Training in Chennai
German Classes in Chennai
German Language Classes in Chennai
German Language course in Chennai
Post a Comment