Monday, December 3, 2012

Allowing cross domain persistence sync to backend database


PersistenceJS comes with client-server example for syncing to backend database. But, when a project complexity reaches a certain level, cross-domain persistence store access might be required. There are many ways to tweak the script for allowing cross-domain access. I was looking for a simple and elegant way to handle this issue, and I found non-other than tweaking the http-header. Tweaking the http-header is a common way to bypass same domain policy.

The purpose of this article is demonstrate the steps to tweak Nodejs web server to support cross domain request so that persistence client hosted on different domain can perform a database sync on the Nodejs web server.

The Server-Side - Setting the http-header
Below is a sample app.js based on todo-app (see my earlier post :). The example below shows the server-side scripting that is required to allow cross-domain access for persistence. The changes are highlighted in YELLOW.

var strVcap = process.env.VCAP_SERVICES || '{"mysql-5.1":[{"name":"mysql-d70a3","label":"mysql-5.1","plan":"free","tags":["mysql","mysql-5.1","relational"],"credentials":{"name":"todoappdb","hostname":"localhost","host":"localhost","port":3306,"user":"root","username":"root","password":"MyNewPass"}}]}';
var jsonVcap = JSON.parse(strVcap);

//persistence declaration
var persistence = require('persistencejs/lib/persistence').persistence;
var persistenceStore = require('persistencejs/lib/persistence.store.mysql');
var persistenceSync = require('persistencejs/lib/persistence.sync.server');

persistenceStore.config(persistence, jsonVcap["mysql-5.1"][0].credentials.host, jsonVcap["mysql-5.1"][0].credentials.port, jsonVcap["mysql-5.1"][0].credentials.name, jsonVcap["mysql-5.1"][0].credentials.username, jsonVcap["mysql-5.1"][0].credentials.password);
persistenceSync.config(persistence);

//init sync
var Todo = persistence.define('todo', {
content: 'TEXT',
done: 'BOOL'
});
Todo.enableSync(); //this create table with sync attribute

//nodejs module declaration
var express = require("express");
var app = express();

//init express
app.use(express.static(__dirname));
app.use(express.bodyParser());
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
var end = res.end;

req.conn = persistenceStore.getSession();
req.conn.schemaSync();
res.end = function() {
req.conn.close();
end.apply(res, arguments);
};
req.conn.transaction(function(tx) {
req.tx = tx;
next();
});
});

app.get('/todoUpdates',  function(req, res) {
console.log(" - get /todoUpdates - " + req.params.uid);
persistenceSync.pushUpdates(req.conn, req.tx, Todo, req.query.since, function(updates) {
res.send(updates);
    });
});

app.post('/todoUpdates',  function(req, res) {
console.log(" - post /todoUpdates - " + req.params.uid);
persistenceSync.receiveUpdates(req.conn, req.tx, Todo, req.body, function(result) {
res.send(result);
});
});

app.get('/markAllDone', function(req, res) {
    Todo.all(req.conn).list(req.tx, function(todo) {
        todo.forEach(function(todo) {
            todo.done = true;
          });
        req.conn.flush(req.tx, function() {
            res.send({status: 'ok'});
                });
      });
});

app.get('/markAllUndone', function(req, res) {
    Todo.all(req.conn).list(req.tx, function(todo) {
        todo.forEach(function(todo) {
            todo.done = false;
          });
        req.conn.flush(req.tx, function() {
            res.send({status: 'ok'});
          });
      });
});

app.listen(process.env.VCAP_APP_PORT || 3303);
console.log('-- Server running at http://127.0.0.1:3303/ --');

The Client-Side - Pointing to the allowed server
Below is a sample persistence client configured to sync to the crossed domain server. The example below shows the client-side script changes required to set to a cross domain server (as highlighted in YELLOW).

Todo.enableSync('http://localhost:3303/todoUpdates');

In Conclusion
By allowing cross domain access to a persistence data store, constraint on web-platform to use only the data store within the same site is eliminated. Thus, all your other web application will be able to use the data store in the web server. This will impact on your web application design (example, single page application or web-portal). On the other hand, there will be needs to properly secure the web server from unwanted attacks.

The example of this tutorial can be downloaded here



Monday, September 10, 2012

How to setup PersistenceJS database sync using NodeJS and MySQL

Today, Javascript is capable of access to back-end database, thanks to ORM (Object-Relational-Mapper). Day by day, ORM frameworks are mushrooming on the net. I was looking for a framework that build database seamlessly, pure and simple, and I found a Javascript ORM framework called PersistenceJS.  PersistenceJS has the front-end and back-end library that make it easy to implement ORM.

The purpose of this tutorial is to setup a database synchronization for your PersistenceJS client-side web application. I use todo example (by Jacob) for this experiment, and the backend is powered by MySQl, NodeJS and persistencejs sync plugin. In short, here are the prequisites:


Stack on the back-end side:
For front-end library:

First, building app.js for NodeJS (server-side scripting)

Declare & Init PersistenceJS (refer to persistencejs example)

//persistence declaration
var persistence = require('persistencejs/lib/persistence').persistence;
var persistenceStore = require('persistencejs/lib/persistence.store.mysql');
var persistenceSync = require('persistencejs/lib/persistence.sync.server');

persistenceStore.config(persistence, "localhost", 3306, "todoappdb", "root", "yourpassword");
persistenceSync.config(persistence); 

//init sync
var session = persistenceStore.getSession();
var Todo = persistence.define('todo', {
content: 'TEXT',
done: 'BOOL'
});
Todo.enableSync(); //this create table with sync attribute
session.schemaSync(); //generate the table

Declare & Init Express


//nodejs module declaration
var express = require("express");
var app = express();

//init express
app.use(express.static(__dirname));
app.use(express.bodyParser());
app.get('/todoUpdates',  function(req, res) {
console.log(" - get /todoUpdates - ");
//var session = persistenceStore.getSession();
session.transaction(function(tx){
persistenceSync.pushUpdates(session, tx, Todo, req.query.since, function(updates) {
res.send(updates);
    });
});
});
app.post('/todoUpdates',  function(req, res) {
    console.log(" - post /todoUpdates - ");
//var session = persistenceStore.getSession();
session.transaction(function(tx){
persistenceSync.receiveUpdates(session, tx, Todo, req.body, function(result) {
res.send(result);
});
});
});

app.listen(3000);

A little change on the client-side, editing services.js from jacob todo example.


Add this line of code after you define your Todo object.

Todo.enableSync('/todoUpdates'); //this will create the table with sync attributes


In the persistence.flush() function, just call the todo.syncall function (to update the back-end).


persistence.flush(function(){
Todo.syncAll(
function(){alert('Your Callback Code');},
function(){alert("Your Sync Complete Code");},
function(){alert("Your Error Handling Code");}
);
});


Finally, start nodejs (e.g. "node app.js" in your command prompt) and navigate to 
http://localhost:3002/todo.html

The example of this tutorial can be found here 

http://azee01.ap01.aws.af.cm/todo.html

Download link here
https://github.com/anthonyzee/todo-example-sync