Introduction
This article lets you through a sample application developed using Node.js, Express Framework and using MongoDB as backend.
We’ll be covering an application walkthrough build with the following technologies:
- Server Side - Node.Js
- ClientSide - Jquery, HTML, CSS
- View Parser Engine - Jade
- Development framework - Express Framework
- Database - MongoDB
Express Framework: Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
Node.js: Node.js is an open source, cross-platform runtime environment for server-side and networking applications. Node.js applications are written in JavaScript, and can be run within the Node.js runtime on OS X, Microsoft Windows, Linux and FreeBSD.
MongoDB: MongoDB is an open source database that uses a document-oriented data model. MongoDB is one of several database types to arise in the mid-2000s under the NoSQL banner. Instead of using tables and rows as in relational databases, MongoDB is built on an architecture of collections and documents.
Prerequisites
Resources:
Installing Node Package Manager (npm):
http://nodejs.org/download/
Setting Up Visual Studio for Express Framework Template:
https://nodejstools.codeplex.com/wikipage?title=Installation
MongoDb related resources - Installation, Running, DB Queries:
http://docs.mongodb.org/manual/
Jade Templating Engine:
http://jade-lang.com/tutorial/
Using the Code
Setting Up
- Install node package manager from http://nodejs.org/download/
- Install nodejstools from https://nodejstools.codeplex.com/wikipage?title=Installation
- Install MongoDb from http://www.mongodb.org/downloads
If you have successfully installed nodejs tools for Visual Studio, you would be able to create an Express Application as shown below:
We're covering up on 3 main elements used in the application:
- Node.js code - Server side
- Jade Parser - Presentation side
- Database operations
Project Architecture
Project Structure
- public>js>
Contains the JavaScript logic (jquery, validators) for the corresponding views.
- public>vendor>
Global JavaScripts, stylesheets, fonts.
- server>modules>
Database managers, Utility functions for server side code. E.g.: Sending mail utility.
- server>views>
Contains jade views.
- node_modules
Contains libraries used in the application.
Start MongoDb daemon/server first and then run the project.
Express Framework
package.json
This is the configuration for the application. It specifies the dependencies(modules/libraries) needed for the application and will get installed if it does not exist on running the 'npm install
' command in the Package Manager Console of Visual Studio.
{
"name": "ExpressApp2",
"version": "0.0.0",
"description": "ExpressApp2",
"main": "app.js",
"author": {
"name": "tushar.gupta",
"email": ""
},
"dependencies": {
"emailjs": "^0.3.3",
"express": "3.4.4",
"jade": "*",
"stylus": "*",
"moment": "^1.7.2",
"mongodb": "*"
}
}
app.js
This file sets the initialisation parameters for the node.js application.
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
app.set('port', 3000);
app.set('views', path.join(__dirname, '/app/server/views'));
app.set('view engine', 'jade');
app.locals.pretty = true;
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'super-duper-secret-secret' }));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(require('stylus').middleware(path.join(__dirname, '/app/public')));
app.use(express.static(path.join(__dirname, '/app/public')));
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
require('./app/server/router')(app);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
router.js
This file acts as a controller and responds to the request from client. It sets up the data for the view (from services/database) and sends the response.
app.get('/', function (req, res) {
if (req.cookies.user == undefined || req.cookies.pass == undefined) {
res.render('login', { title: 'IB-Wall - Please Login To Your Account' });
} else {
AM.autoLogin(req.cookies.user, req.cookies.pass, function (o) {
if (o != null) {
req.session.user = o;
res.redirect('/user/' + req.cookies.user);
} else {
res.render('login', { title: 'IB-Wall - Please Login To Your Account' });
}
});
}
});
app.post('/', function (req, res) {
AM.manualLogin(req.param('user'), req.param('pass'), function (e, o) {
if (!o) {
res.send(e, 400);
} else {
req.session.user = o;
res.cookie('user', o.user, { maxAge: 900000 });
res.cookie('pass', o.pass, { maxAge: 900000 });
res.send(o, 200);
console.log('user login and redirecting to home');
}
});
});
app.get('/user/:username', function (req, res) {
if (req.session.user == null) {
res.redirect('/');
} else {
var uName = req.param('username');
AM.getAllRecords(function (e, accounts) {
AM.getUserByUname(uName, function (e, onWQallOfuser) {
AM.getPostsForUser(onWQallOfuser, function (e, userPosts) {
var uPosts = [];
uPosts = userPosts;
res.render('index', {
title : 'Welcome to IB-Wall',
udata : req.session.user,
wallUserData: onWQallOfuser,
accounts: accounts,
userPosts: uPosts
});
});
});
});
}
});
app.post('/logoutuser', function (req, res) {
if (req.param('logout') == 'true') {
res.clearCookie('user');
res.clearCookie('pass');
req.session.destroy(function (e) { res.send('ok', 200); });
}
});
JADE - View Templating Engine
index.jade
This is the View file which renders the HTML to the client.
You can convert your HTML code to jade code using many online converters available.
You can learn more about jade from online resources.
Jade follows indentation styling to group elements.
extends walllayout
block content
include userdetails
.wrapper
.box
.row.row-offcanvas.row-offcanvas-left
// sidebar
#sidebar.column.col-sm-2.col-xs-1.sidebar-offcanvas
ul.nav
li
a.visible-xs.text-center(href='#', data-toggle='offcanvas')
i.glyphicon.glyphicon-chevron-right
ul#lg-menu.nav.hidden-xs
each account in accounts
li.active
a(href='http://www.codeproject.com/user/#{account.user}')
img.img-circle(src='http://www.codeproject.com/placehold.it/150x150', width='25px', height='25px')
| #{account.name}
Getting the data from the server variables and Setting for use in the view.
userdetails.jade
// preset form values if we receive a userdata object //
//variables are declared by using '-' sign
//Data from server can be get just by using the same variable name as declared on server end.
- user = typeof(udata) != 'undefined' ? udata : { }
- wallUser = typeof(wallUserData) != 'undefined' ? wallUserData : { }
// store the userId on the client side in a hidden input field //
input(type='hidden', value= user._id)#userId
input(type='hidden', value= wallUser._id)#wallUserId
input(type='hidden', value= user.name)#LoginUserFullName
input(type='hidden', value= wallUser.name)#wallUserFullName
// display form errors in a custom modal window //
include modals/form-errors
Setting a master page in other jade pages
extends walllayout
Setting containers in master page and using in child pages
block content
Including a jade in other jade page
include userdetails
Below code shows how to insert script into jade pages
script(src='http://www.codeproject.com/vendor/javascripts/scripts.js')
Below code shows how to set title and insert style into jade pages
head
title= title
link(rel='stylesheet', href='http://www.codeproject.com/vendor/stylesheets/bootstrap_wall.min.css')
Database Operations
AccountManager.js
This file is responsible for the following operations:
- Setting up connection to mongodb database.
- Writing functions to fetch data from database.
Setting up connection to mongodb database
var crypto = require('crypto');
var MongoDB = require('mongodb').Db;
var Server = require('mongodb').Server;
var moment = require('moment');
var dbPort = 27017;
var dbHost = 'localhost';
var dbName = 'manthandb-oaapt';
var db = new MongoDB(dbName, new Server(dbHost, dbPort, { auto_reconnect: true }), { w: 1 });
db.open(function (e, d) {
if (e) {
console.log(e);
} else {
console.log('connected to database :: ' + dbName);
}
});
var accounts = db.collection('accounts');
var posts = db.collection('posts');
var likes = db.collection('userlikes');
Database queries
exports.addNewPost = function (data, callback) {
data.createdDate = moment().format('MMMM Do YYYY, h:mm:ss a');
posts.insert(data, function (e, postAdded) {
if (!e) {
callback(null, postAdded);
}
});
}
exports.autoLogin = function (user, pass, callback) {
accounts.findOne({ user: user }, function (e, o) {
if (o) {
o.pass == pass ? callback(o) : callback(null);
} else {
callback(null);
}
});
}
exports.getAllRecords = function (callback) {
accounts.find().toArray(
function (e, res) {
if (e) callback(e)
else callback(null, res)
});
};
exports.deleteAccount = function (id, callback) {
accounts.remove({ _id: getObjectId(id) }, callback);
}
Points of Interest
The article provided a overview of Facebook style application.
For details, please run the application.