Prash's Blog

Sticky Notes App in Nodejs using MongoDb May 16, 2012

Filed under: Nodejs — prazjain @ 4:10 pm
Tags: , , , ,

In this example we will see the interactivity between MongoDB and Nodejs.

We will create a “Post It” / “Sticky Notes” application in Nodejs and save the data in MongoDb.

Please check the other post for setting up mongodb with nodejs for this example..

Install npm packages for express, ejs, async :

npm install express ejs async

Now if you have followed back from the first article, then add the following methods to postitdb.js


// create the schema
var PostItSchema = new Schema(
{
	ts : { type: Date, default: Date.now },
	author : String,
	note : String
});

// register the schema
mongoose.model('PostIt',PostItSchema);

// create instance of the model
var Note = mongoose.model('PostIt');
exports.emptyNote = { "_id": "", author: "", note:""};

// define and export the add function to add a new note
exports.add = function(author, note, callback)
{
	var newNote = new Note();
	newNote.author = author;
	newNote.note = note;
	// to save a new note all you need to do it call save on it
	newNote.save(function(err)
	{
		if (err)
		{
			util.log('FATAL ' + err);
			callback(err);
		}
		else
		{
			callback(null);
		}
	});
};

// define and export the delete function
exports.delete = function(id,callback)
{
	// find the note by id then delete it by calling remove
	exports.findNoteById(id, function(err,doc)
	{
		if(err)
		{
			callback(err);
		}
		else
		{
			util.log(util.inspect(doc));
			doc.remove();
			callback(null);
		}
	});
};

// define and export the edit function
exports.edit = function(id, author, note, callback)
{
	// fine the note by id and edit it then save the changes.
	exports.findNoteById(id, function(err, doc)
	{
		if (err)
		{
			callback(err);
		}
		else
		{
			doc.ts = new Date();
			doc.author = author;
			doc.note = note;
			doc.save(function(err)
			{
				if(err)
				{
					util.log('FATAL ' + err);
					callback(err);
				}
				else
				{	
					callback(null);
				}
			});
		}
	});
};

// define and export allNotes function
exports.allNotes = function(callback)
{
	// we will get all notes from the db if we do not give any conditional expression
	Note.find({}, callback);
};

// define and export forAll function
exports.forAll = function(doEach, done)
{
	// we will get all notes from the db if we do not give any conditional expression
	// then invoke doEach function on every row
	Note.find({}, function(err, docs)
	{
		if(err)
		{
			util.log('FATAL ' + err);
			done(err,null);
		}
		docs.forEach(function(doc)
		{
			doEach(null,doc);
		});
		done(null);
	});
};

// define findNoteById and exports it.
var findNoteById = exports.findNoteById  = function(id, callback)
{
	Note.findOne({_id: id} , function(err,doc)
	{
		if (err)
		{
			util.log('FATAL ' + err);
			callback(err,null);
		}
		callback(null,doc);
	});
};

Now lets create app.js which holds all the logic for routing and connecting different bits to each other.

var util = require('util');
var url = require('url');
var express = require('express');
var postitdb = require('./postitdb');
var app = express.createServer();
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.register('.html',require('ejs'));
app.set('views',__dirname + '/views');
app.set('view engine','ejs');

var parseUrlParams = function(req,res,next)
{
	req.urlP = url.parse(req.url,true);
	next();
}

var checkAccess = function(req,res,next)
{
	// a logged-in user will have "AOK" set in his cookies
	if (!req.cookies || !req.cookies.notesaccess || req.cookies.notesaccess !== "AOK")
	{
		res.redirect('/login');
	}
	else
	{
		next();
	}
};

postitdb.connect(function(error)
{
	if (error) throw error;
});

app.on('close', function(errno)
{
	postitdb.disconnect(function(err) {} );
});

app.get('/', function (req,res) { res.redirect('/view'); } );

app.get('/login', function(req,res)
{
	res.render('login.html', { title: "Notes LOGIN" });
});

app.post('/login', function(req,res)
{
	if (req.body.username== "gabbarsingh" && req.body.pwd=="kalia")
	{
		res.cookie('notesaccess','AOK');
		res.redirect('/view');		
	}
	else
	{
		util.log('Cannot match username and password');
	}
});

app.get('/view', parseUrlParams, checkAccess, function (req,res)
{
	postitdb.allNotes(function(err, notes)
	{
		if(err)
		{
			util.log('ERROR ' + err);
			throw err;
		}
		else 
		{
			res.render('viewnotes.html', { title : "Notes", notes: notes });
		}
	});
});

app.get('/add', parseUrlParams, checkAccess, function(req,res) 
{
	res.render('addedit.html', { title : "Notes", postpath: '/add', note: postitdb.emptyNote});
});

app.post('/add', checkAccess, function(req,res)
{
	postitdb.add(req.body.author, req.body.note, function(error)
	{
		if (error) throw error;
		res.redirect('/view');
	});
});

app.get('/del', parseUrlParams, checkAccess, function(req,res)
{
	postitdb.delete(req.urlP.query.id, function(error) 
	{
		if(error) throw error;
		res.redirect('/view');
	});
});

app.get('/edit', parseUrlParams, checkAccess, function(req,res)
{
	postitdb.findNoteById(req.urlP.query.id, function(error, note) 
	{
		if (error) throw error;
		res.render('addedit.html', {title : "Notes", postpath:'/edit', note: note });
	});
});
app.post('/edit', checkAccess, function(req,res)
{
	postitdb.edit(req.body.id, req.body.author, req.body.note, function(error)
	{
		if (error) throw error;
		res.redirect('/view');
	});
});
app.listen(3000);

Now we just need to give html files for rendering the output.
Create a views directory that will be used by ejs to render html from html files from this directory as registered earlier.

mkdir views

Create all the html files mentioned below in “views” directory.
layout.html

<html>
	<head><title><%= title %></title></head>
	<body>
		<h1><%= title %></h1>
		<p><a href='/view'>View</a> | <a href='/add'>Add</a></p>
		<%- body %>
	</body>
</html>

viewnotes.html

<table><% notes.forEach(function(note) 
{ %>
	<tr><td>
			<p><%= new Date(note.ts).toString() %>: by <b> <%= note.author %></b></p>
			<p><%= note.note %></p>
		</td>
		<td>
			<form method='GET' action='/del'>
				<input type='submit' value='Delete'/>
				<input type='hidden' name='id' value='<%= note._id %>' />
			</form>
			<br/>
			<form method='GET' action='/edit'>
				<input type='submit' value='Edit' />
				<input type='hidden' name='id' value='<%= note._id %>' />
			</form>
		</td>
	</tr>
<% }); %></table>

addedit.html

<form method='POST' action='<%= postpath %>'>
	<% if(note) 
	{ %>
		<input type='hidden' name='id' value='<%= note._id %>' />
	<% } %>
		<input type='text' name='author' value='<%= note.author %>' />
		<br/>
		<textarea rows=5 cols=40 name='note'>
		<%= note.note %>
		</textarea>
		<br/>
		<input type='submit' value='Submit' />
</form>

login.html

<form method='POST' action='/login'>
	<p>Click the <i>Login</i> to log in.</p>
	<table>
		<tr>
			<td>Username: </td>
			<td><input type='text' name='username' length=30 /></td>
		</tr>
		<tr>
			<td>Password: </td>			
			<td><input type='password' name='pwd' length=30 /></td>
		</tr>
		<tr>
			<td><input type='submit' value='Login' /></td>
			<td><input type='reset' value='Clear' /></td>
		</tr>
	</table>
</form>

That is all you need, and now you can run the application using

node app

And visit the url : http://localhost:3000, Voila!

 

Simple MongoDb example for Nodejs May 15, 2012

Filed under: Nodejs — prazjain @ 3:25 pm
Tags: , , ,

In this example we will see the interactivity between MongoDB and Nodejs.

We will create a “Post It” application in Nodejs and save the data in MongoDb.

Install npm package for async, mongoose :

npm install async mongoose

Use mongoose to interact with MongoDb in postitdb.js as below :


var util = require('util');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dburl = 'mongodb://localhost/postitnotes';

exports.connect = function (callback) 
{
	mongoose.connect(dburl);
};

exports.disconnect = function (callback)
{
	mongoose.disconnect(callback);
};

exports.setup = function(callback)
{
	// dummy implemetation right now, add anything else you want to do during setup
	callback(null);
};

Setup the database, create setup.js

var util = require('util');
var async = require('async');
var postitdb = require('./postitdb');

postitdb.connect(function(error)
{
	if (error) throw error;
});

postitdb.setup(function(error)
{
	if (error)
	{
		util.log('ERROR ' + error);
		throw error;
	}
	async.series([
		function(cb)
		{
			postitdb.add("2012",
				"Plans for summer 2012 concerts! Make some noise!",
				function(error)
				{
					if (error) util.log('ERROR '+ error);
					cb(error);
				});
		}
		],
		function(error, results)
		{
			if (error) util.log('ERROR ' + error);
			postitdb.disconnect(function(err) {} );
		}
		);
});

Now lets have another script just to check if the db was setup correctly

Create show.js

var util = require('util');
var postitdb = require('./postitdb');

postitdb.connect(function(error)
{
	if(error) throw error;
});

postitdb.forAll(function(error, row)
	{
		util.log('ROW : ' + util.inspect(row));
	}
	, function(error)
	{
		if (error) throw error;
		util.log('ALL DONE' );
		postitdb.disconnect(function(err) { } );
	}
);

Run mongod from MongoDb bin directory

cd c:\mongodb\bin
mongod

Now you are ready to setup database

node setup

To verify if the database was setup correctly, run show.js as below

node show

If you are able to see the record created above for 2012 plans in command prompt, then you are in good company!

We will expand on this example later to make the complete app. To be continued …

EDIT: Follow up post to make the complete Sticky Notes / Post It Application

 

A simple Expressjs application May 2, 2012

Filed under: Nodejs — prazjain @ 1:35 pm
Tags: ,

This is part of a multipart nodejs series.

Now we will port the example to use Expressjs.

npm install express ejs qs

Start with writing a module app-express.js
Here we set ejs as the template engine for express. And as you can see below Express simplifies a lot of routing logic for us.

var htutil = require('./htutil');
var math = require('./math');
var express = require('express');
var app = express.createServer();

app.register('.html', require('ejs'));

app.set('view engine', 'ejs');

app.get('/',function(req,res)
{
	res.render('home.html', {title : "Math App" } );
});

app.get('/mult',	htutil.loadParams, function (req, res )
{
	if (req.a && req.b) res.result = req.a * req.b;
	res.render('mult.html', { title : "Math App", req: req });
});

app.get('/square', 	htutil.loadParams, function (req, res )
{
	if (req.a) req.result = req.a * req.a ;
	res.render('square.html', {title: "Math App", req: req });
});

app.get('/fibonacci', 	htutil.loadParams, function (req, res )
{
	if (req.a) 
	{
		math.fibonacciAsync(Math.floor(req.a), function(val)
		{
			req.result = val;
			res.render('fibo.html', {title: "Math App", req: req });
		});
	}
	else 
	{
		res.render('fibo.html', { title : "Math App", req:req });
	}
});

app.get('/factorial', htutil.loadParams, function(req, res)
{
	if (req.a)
	{
		req.result = math.factorial(req.a);
	}
	res.render('factorial.html', {title : "Math App", req: req });
});

app.get('/404', function(req,res) 
{
	res.send('NOT FOUND' + req.url);
});

app.listen(8124);
console.log('listening to http://localhost:8124');

Create a views directory

mkdir views

Create the html files for template in the views directory. EJS templating engine will pick up these files automatically.
We will have a layout.html which will have the common html code.

<html>
<head><title><%= title %></title></head>
<body>
<h1><%= title %></h1>
<table>
<tr><td>
<div class='navbar'>
<p><a href='/'>home</a></p>
<p><a href='/mult'>Multiplication</a></p>
<p><a href='/square'>Square's</a></p>
<p><a href='/factorial'>Factorial's</a></p>
<p><a href='/fibonacci'>Fibonacci's</a></p>
</div>
</td>
<td><%- body %></td>
</tr>
</table></body></html>

Now we need to have template html files for the four operations.
Home.html

<p>Math App</p>

mult.html

<% if (req.a && req.b) { %>
<p class='result'>
<%= req.a %> * <%= req.b %> = <%= req.result %>
</p>
<% } %>
<p>Enter numbers to multiply</p>
<form name='mult' action='/mult' method='get'>
A: <input type='text' name='a' /><br/>
B: <input type='text' name='b' />
<input type='submit' value='Submit' />
</form>

square.html

<% if (req.a) { %>
<p class='result'>
<%= req.a %> squared = <%= req.result %>
</p>
<% } %>
<p>Enter numbers to multiply</p>
<form name='square' action='/square' method='get'>
A: <input type='text' name='a' />
<input type='submit' value='Submit' />
</form>

factorial.html

<% if (req.a) { %>
<p class='result'>
<%= req.a %> factorial = <%= req.result %>
</p>
<% } %>
<p>Enter a number to see it's factorial</p>
<form name='factorial' action='/factorial' method='get'>
A: <input type='text' name='a' />
<input type='submit' value='Submit' />
</form>

fibo.html

<% if (req.a) { %>
<p class='result'>
fibonacci <%= req.a %> = <%= req.result %>
</p>
<% } %>
<p>Enter a number to see it's fibonacci</p>
<form name='fibonacci' action='/fibonacci' method='get'>
A: <input type='text' name='a' />
<input type='submit' value='Submit' />
</form>

Now you can run the app like this

node app-express.js

And hit the url : http://localhost:8124.
Go back to the main nodejs tutorial.

 

Split nodejs blocking operation using process.nextTick

Filed under: Nodejs — prazjain @ 9:16 am
Tags:

This is part of a multipart nodejs series.
In the previous post for basic nodejs application, you have seen a blocking / long running user operation hogging cpu in node. Single node is single threaded and runs only on a single core, a single blocking request and bring your web app to a halt. To get away with this, you can use process.nextTick to execute a particular function through the event loop.
Here we will refine on the fibonacci function defined earlier, and add a new function in math.js :

var fibonacciAsync = exports.fibonacciAsync = function(n, done)
{
	if (n==1 || n ==2)
	{
		done(1);
	}
	else
	{
		process.nextTick(function() 
		{
			fibonacciAsync( n -1 , function(val1)
			{
				process.nextTick(function() 
				{
					fibonacciAsync( n -2, function(val2)
					{
						done(val1 + val2);
					});
				});
			});
		});
	}
}

Create another module fibo2-node.js :

var htutil = require('./htutil');
var math = require('./math');
function sendResult(req, res, a, fiboval)
{
	res.writeHead(200, { 'Content-Type': 'text/html' } );
	res.end(htutil.page("Fibonacci", htutil.navbar(), 
				[
				(!isNaN(fiboval) ? ("<p class='result'>fibonacci {a} = {fibo}</p>"
				.replace("{a}",a)
				.replace("{fibo}",fiboval))
				: "" ),
				"<p>Enter a number to see its fibonacci</p>",
				"<form name='fibonacci' action='/fibonacci' method='get'>",
				"A: <input type='text' name='a' />",
				"<input type='submit' value='Submit' />",
				"</form>"
				].join('\n')
				)
			);				
}

exports.get = function(req, res)
{
	if(!isNaN(req.a))
	{
		math.fibonacciAsync(Math.floor(req.a), function(val)
		{
			sendResult(req,res, Math.floor(req.a), val);
		});
	}
	else
	{
		sendResult(req,res,NaN,NaN);
	}
}

Change app-node.js to call fibo2-node module when it get /fibonacci requests like this :

                                        .....
					else if (req.params.pathname === "/fibonacci")
					{
						require("./fibo2-node").get(req,res);
					}
                                        .....

Now if you run the app :

node app-node.js

Hit the url : http://localhost:8124, for fibonacci enter the value like 50, while it is processing this request, in another window open the same url and you can see that the server can handle the new request. This is because the earlier fibonacci implementation would hog all the cpu for itself until it finished the computation and no other request will be processed. But now the cpu is responsive to other requests as well.

An interesting observation here is that if you try fibonacci for 40 in previous implementation it will probably return in few seconds, but with new implementation my request timed-out, which is probably a side-effect of spilt a small task into a large number of very small task to keep the cpu responsive to other requests.
Go back to the main nodejs tutorial.

 

A simple example using Nodejs, Connectjs, Expressjs May 1, 2012

Filed under: Nodejs — prazjain @ 2:41 pm
Tags: , ,

I will make it a 4 part series where we will create a webapp in Nodejs, improvise that app in Nodejs, and then use Connectjs and Expressjs to improve the example.

  1. Basic web app using Nodejs.
  2. Execute tasks asynchronously in Nodejs event loop.
  3. Use Expressjs.
 

Basic Nodejs Application

Filed under: Nodejs — prazjain @ 11:57 am
Tags:

This is part of a multipart nodejs series.

Here I will write a basic nodejs application and then we will go ahead and make changes to this app to make it faster and better as we go along.
Lets make a calculator web application in nodejs. We do not need any external dependencies for this application.

PS: In some places you will need to change ” (double quote) for a ‘ (single quote) in javascript for the code below. WordPress goes mental if I use ‘ (single quote) in my javascript code.
PS2 : WordPress also goes mental if I use div tag in my code!

In app-node.js we are creating a http server and redirecting particular requests to particular modules. Code for the modules follows later.
Create module app-node.js with contents from below.

var http_port = 8124;
var http = require("http");
var htutil =require("./htutil");

var server = http.createServer(function(req,res)
				{
					htutil.loadParams(req,res,undefined);
					if (req.params.pathname==="/")
					{
						require("./home-node").get(req,res);
					}
					else if (req.params.pathname==="/square")
					{
						require("./square-node").get(req,res);
					}
					else if (req.params.pathname === "/factorial")
					{
						require("./factorial-node").get(req,res);
					}
					else if (req.params.pathname === "/fibonacci")
					{
						require("./fibo-node").get(req,res);
					}
					else if (req.params.pathname === "/mult")
					{
						require("./mult-node").get(req,res);
					}
					else
					{
						res.writeHead(404,{"Content-Type":"text/plain"});
						res.end("bad URL " + req.url);
					}
				});
server.listen(http_port);
console.log("listening to http://localhost:8124");

For Module htutil.js, use the code below. This module does a few things:
1) Parses request parameters into variables a and b and invokes a chaining function if defined.
2) Creates a navigation bar in the web app, to navigate / invoke different requests.
3) A function to render the html for web page. This takes 3 params, the title for the page, navigation bar contents and web page contents.

var url = require("url");
exports.loadParams = function(req,res,next)
{
	req.params = url.parse(req.url,true);
	req.a = (req.params.query.a && !isNaN(req.params.query.a)) ? new Number (req.params.query.a) : NaN ;
	req.b = (req.params.query.b && !isNaN(req.params.query.b)) ? new Number (req.params.query.b) : NaN ;
	if (next) next();
}
exports.navbar = function()
{
	return ["<div class="navbar">",
			"<p><a href="/">home</a></p>",
			"<p><a href="/mult">Multiplication</a></p>",
			"<p><a href="/square">Square</a></p>",
			"<p><a href="/factorial">Factorial</a></p>",
			"<p><a href="/fibonacci">Fibonacci</a></p>",
			"</div>"].join("\n");
}
exports.page= function (title, navbar, content)
{
	return ["<html><head><title>{title}</title></head>",
			"<body><h1>{title}</h1>",
			"<table><tr>",
			"<td>{navbar}</td><td>{content}</td>",
			"</tr></table></body></html>"
			].join("\n2")
			.replace(/{title}/g,title)
			.replace(/{navbar}/g,navbar)
			.replace(/{content}/g,content);
}

Now lets write module that will actually perform these calculation, there is not much to explain in them so I will just write them down.

mult-node.js

var htutil = require("./htutil");
exports.get=function(req,res)
{
	res.writeHead(200, { "Content-Type":"text/html" });
	var result = req.a * req.b;
	res.end(htutil.page("Multiplication", htutil.navbar(),
							[
							(!isNaN(req.a) && !isNaN(req.b) ?
								("<p class="result">{a} * {b} = {result}</p>"
								.replace("{a}", req.a)
								.replace("{b}", req.b)
								.replace("{result}", req.a * req.b))
								: ""
							),
							"<p>Enter numbers to multiply</p>",
							"<form name="mult" action="/mult" method="get">",
							"A: <input type="text" name="a" /><br/>",
							"B: <input type="text" name="b" /><br/>",
							"<input type="submit" value="Submit" />",
							"</form>"
							].join("\n")
						)
			);
}

Module square-node.js

var htutil = require("./htutil");
exports.get=function(req,res)
{
	res.writeHead(200, { 'Content-Type':'text/html' });
	res.end(htutil.page("Square", htutil.navbar(),
							[
							(!isNaN(req.a) ?
								("<p class='result'>{a} squared = {sq}</p>"
								.replace("{a}", req.a)
								.replace("{sq}", req.a * req.a))
								: ""
							),
							"<p>Enter number to Square</p>",
							"<form name='square' action='/square' method='get'>",
							"A: <input type='text' name='a' /><br/>",
							"<input type='submit' value='Submit' />",
							"</form>"
							].join('\n')
						)
			);
}

Module home-node.js

var htutil = require('./htutil');
exports.get = function(req,res)
{
	res.writeHead(200, { 'Content-Type':'text/html'});
	res.end(htutil.page("Math App", htutil.navbar(), "<p>Math App</p>"));
}

Module factorial-node.js

var htutil = require("./htutil");
var math = require('./math');
exports.get=function(req,res)
{
	res.writeHead(200, { 'Content-Type':'text/html' });
	res.end(htutil.page("Factorial", htutil.navbar(),
							[
							(!isNaN(req.a) ?
								("<p class='result'>{a} factorial = {fact}</p>"
								.replace("{a}", req.a)
								.replace("{fact}", math.factorial(Math.floor(req.a))))
								: ""
							),
							"<p>Enter number to find factorial</p>",
							"<form name='factorial' action='/factorial' method='get'>",
							"A: <input type='text' name='a' /><br/>",
							"<input type='submit' value='Submit' />",
							"</form>"
							].join('\n')
						)
			);
}

Module fibo-node.js

var htutil = require("./htutil");
var math = require('./math');
exports.get=function(req,res)
{
	res.writeHead(200, { 'Content-Type':'text/html' });
	res.end(htutil.page("Fibonacci", htutil.navbar(),
							[
							(!isNaN(req.a) ?
								("<p class='result'>{a} fibonacci series = {fibo}</p>"
								.replace("{a}", Math.floor(req.a))
								.replace("{fibo}", math.fibonacci(Math.floor(req.a))))
								: ""
							),
							"<p>Enter number to find Fibonacci</p>",
							"<form name='fibonacci' action='/fibonacci' method='get'>",
							"A: <input type='text' name='a' /><br/>",
							"<input type='submit' value='Submit' />",
							"</form>"
							].join('\n')
						)
			);
}

Finally the math.js module that has the functions to calculate factorial and fibonacci

var factorial = exports.factorial = function(n)
{
	if (n==0)
		return 1;
	else 
		return n * factorial (n-1);
}

var fibonacci = exports.fibonacci = function (n)
{
	if (n === 1)
		return 1;
	else if (n===2)
		return 1;
	else
		return fibonacci(n-1) + fibonacci(n-2);
}

Now that you have all these modules in same directory, run the command below to start your app

node app-node.js

Now hit the url : http://localhost:8124, to see the app running.
Also note that if you run fibonacci operation, its performance degrades significantly for large values, start with 10, 20, 30, 40. But if you go 50 it will takes hours / days to return back. And while you have run fibonacci operation for 50 through one request, if you try accessing your app through another browser window you will notice that the server does not respond back. This is because node is single threaded and blocks on this operation. In next post we will see how to break this task into several smaller task and execute them which also keep the server responsive enough to handle other requests.

Go back to the main nodejs tutorial.

 

Node.js error Error: Cannot find module XYZ April 24, 2012

Filed under: Nodejs — prazjain @ 9:45 am
Tags: ,

Generally you will see an error like this when a npm node package is not installed properly or not installed in proper location.
Error :

node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Cannot find module 'XYZ'
at Function._resolveFilename (module.js:334:11)
at Function._load (module.js:279:25)
at Module.require (module.js:357:17)
at require (module.js:368:17)

In my case i have seen this happening when I have installed a node module using -g switch, so to fix this I would uninstall the module again and install it without -g switch as shown below :


npm install XYZ