Prerequisites 

GitHub account, Heroku account, Git installed,  MongoDB installed (shell runs) , latest stable Node.js installed (with NPM) so the shell runs

Introduction to MEAN Stack

Basic Concepts :

var args = process.argv;
var result = 0;

for(var i =0; i < args.length; i++){   if(i > 1) {
     result = result + Number(args[]   );
 }
}
console.log(result);

A reference book with examples  –  Rapid Prototype with JS : https://gumroad.com/l/rpjs/A7BB7934

Introduction to Angular JS

http://js/angular.js

    http://js/app.js

    http://js/github_controller.js

 Using Angular Service :

https://github.com/kaniska/angularjs-sample/blob/master/js/github_controller.js

.service(‘GithubService’, function($http) {
this.search = function(q) {
return $http({
method: ‘GET’,
params: {
q: q
}
}).then(function(resp) {
return resp.data;
});
};
})
.controller(‘GithubController’,
function($scope, GithubService) {
$scope.search = function() {
// Run the search on github
// and place results in `results`
GithubService.search($scope.q)
.then(function(data) {
$scope.total_result_count = data.total_count;
$scope.results = data.items;
});
}
})

Advanced Concepts 

Learn Express :

npm install expressworks

Rest API Codehttps://github.com/azat-co/rest-api-express

comparison between Hapi, Sails, Express :

http://runastartup.com/express-js-vs-sails-js-comparison/

Hapi code : github.com/azat-co/practicalnode/blob/master/ch8/rest-hapi/

Validation using JOI modules , Request / Response Event handlers

Built-in Authn , API Configurations

Sails code :

uses Waterline ORM , Generates scaffolds , Bundles static files with Grunt

Single Page Application

https://github.com/azat-co/rpjs/tree/master/board

Backbone :  Router Model Collection View

Flow Control  

CALLBACKS – PART 1

if (error) {

callback(error);

} else {

db.find({}, function() {  }) }

if (error) return callback(error);

db.find({}, function(){ })

CALLBACKS – PART 2

exports.getUsers = function(req, res, next) {

if (req.session.auth && req.session.userId) {

req.db.User.find({}, safeFields, function(err, list) {  

if (err) return next(err); res.status(200).json(list); });

} else { return next(‘User is not recognized.’) } }

  • Async :   ( waterfall, compose, seq, applyEachSerial, queue )

async.waterfall([

   function(callback){  

      callback(null, ‘one’, ‘two’);

},

   function(arg1, arg2, callback) { // arg1 now equals ‘one’ and arg2 now equals ‘two’  

       callback(null, ‘three’); },

   function(arg1, callback) { // arg1 now equals ‘three’  

       callback(null, ‘done’); }

], function (err, result) { // result now equals ‘done’

  });

function promisify(nodeAsyncFn, context)  {

return function() {  

var defer = q.defer() , args = Array.prototype.slice.call(arguments);

args.push(function(err, val) { if (err !== null) {  

return defer.reject(err);

}

return defer.resolve(val);

});

nodeAsyncFn.apply(context || {}, args);  

return defer.promise;

var readFile = promisify(fs.readFile);

readFile(‘test.txt’).then(function(data) { console.log(data); });

Restful Sessions

Redis + Express

npm install connect-redis express-session

var session = require(‘express-session’),

RedisStore = require(‘connect-redis’)(session);

app.use(session({

store: new RedisStore(options),   secret: ‘keyboard cat” }));

Redis Advanced

var SessionStore = require(‘connect-redis’);

var session = require(‘express-session’);

app.use(session({   

    key: ’92A7-9AC’,   secret: ’33D203B7-443B’,   store: new SessionStore({     cookie:domain: ‘.webapplog.com’ },     db: 1, // Redis DB    host: ‘webapplog.com’ }));

Clustering the app in a box

var cluster = require(‘cluster’);

var http = require(‘http’);    

var numCPUs = require(‘os’).cpus().length;    

var express = require(‘express’);

if (cluster.isMaster) {

console.log (‘ Fork %s worker(s) from master’, numCPUs)    

  for (var i = 0; i < numCPUs; i++) {     cluster.fork();   };

cluster.on(‘online’, function(worker) {

      console.log (‘worker is running on %s pid’, worker.process.pid)   });

cluster.on(‘exit’, function(worker, code, signal) {

      console.log(‘worker with %s is closed’, worker.process.pid);   });

}  else if (cluster.isWorker) {

   var port = 3000;

   console.log(‘worker (%s) is now listening to http://localhost:%s,     cluster.worker.process.pid, port);    

   var app = express();

app.get(‘*’, function(req, res) {

res.send(200, ‘cluser ‘       + cluster.worker.process.pid       + ‘ responded \n’);   })

app.listen(port);

}

Error Handling

server.on('error', function (err) {   console.error(err);   ... })
process.on('uncaughtException', function (err) {
  console.error('uncaughtException: ', err.message);
  console.error(err.stack);
  process.exit(1);
});

process.addListener('uncaughtException', function (err) {
  console.error('uncaughtException: ', err.message);
  console.error(err.stack);
  process.exit(1);
});

Error Notification

  https://gist.github.com/azat-co/67509d5c8e38d2f5f4dd

var sendHipChatMessage = function(message, callback) {

var fromhost = server.set(‘hostname’).replace(‘-‘,).substr(0, 15); //truncate the string

try {

message = JSON.stringify(message);

} catch(e) {}

var data = {

‘format’: ‘json’,

auth_token: server.config.keys.hipchat.servers,

room_id: server.config.keys.hipchat.serversRoomId,

from: fromhost,

message: ‘v’+ server.set(‘version’)+ ‘\nmessage: ‘+ message

};

request({

url:http://api.hipchat.com/v1/rooms/message,

method:‘POST’,

qs: data}, function (e, r, body) {

   if (e) console.error(e);

   if (callback) return callback();

});

};

server.notify = {};

server.notify.error = function(e) {

var message = e.stack || e.message || e.name || e;

sendHipChatMessage(message);

console.error(message);

server.sendgrid.email({

   to: ‘error@webapplog.com,

   from: server.set(‘hostname’) + ‘@webapplog.com,

   subject: ‘Webapp ‘+ server.set(‘version’)+ ‘ error: “‘+ e.name+ ‘”‘,

   category: ‘webapp-error’,

    text: e.stack || e.message

}, exit);

return;

}

Handle Async Error

This is not an error-prone solution

try { // throw new Error(‘Fail!’);

setTimeout(function () {  

       throw new Error(“Fail!”); },

       Math.round(Math.random()*100));

} catch (e) {

       console.log(‘Custom Error: ‘ + e.message);

}

Elegant solution using Domain

Basic Domain Example :  

var domain = require(‘domain’).create();

domain.on(‘error’, function(error) {

console.log(error); });

domain.run(function(){ throw new Error(‘Failed!’); });

Resolve Async Error Handling using Domain

var domain = require(‘domain’);

var d = domain.create();

d.on(‘error’, function(e) { console.log(‘Custom Error: ‘ + e); });

d.run(function() {

setTimeout(function () {  

     throw new Error(‘Failed!’); },  Math.round(Math.random()*100)); });

Domain + Express

http://bit.ly/11ZMLot

Debugging in Nodejs Environment

 

var net = require('net'),
  options = {name: 'azat'};
 
net.createServer(function(socket) {
  repl.start(options.name + "> ", socket).context.app = app;
}).listen("/tmp/debug-app-" + options.name);

  $ ssh ... $ telnet /tmp/repl-app-azat >

Forever + Upstart

$ npm install -g forever

$ forever start -l forever.log -o output.log -e error.log server.js

$ forever stop server.js

$ forever list

$ forever –help

author      “Kaniska”

description “practicalnode”

setuid      “nodeuser”  

start on startup  

stop on shutdown

respawn

env NODE_ENV=production

exec forever start /var/practicalnode/webapp.js >> /var/log/yourprogram.sys.log 2>&1

Serve Static Content using Nginx

sudo vim /etc/nginx/conf.d/virtual.conf

server {     location / {

proxy_pass http://localhost:3000;

}

location /static/ {

root /var/www/webapplog/public;

}

}

$ sudo service nginx start

MongoDB Drivers

For schema less CRUD use  http://mongodb.github.io/node-mongodb-native/contents.html

Use mongoose for ORM . Definitely its slow for complex queries.

NodeJs Frameworks Comparison :

http://slides.com/runastartup/nodejs-frameworks#/

Log Management

Papartrailapp -> aggregate logs from each server in cluster

Bunyan offers log rotation.

Test

superagent (rest test)

casperjs (browser test)

Module Dependency Management

shrinkwrap

Further references :