node.js
practical guide to javascript on server
javascript fast/memory suck:(
node
V8
libuv
OS
single threaded/non blocking
OS
thread
f() f() f() f() f()
iocall1
iocall2
callback1
callback2
heavy functions block server
node
worker worker worker worker
so
what you shouldn't do with
node?
• real real time :)
• data bending
without streams
filesystem
web
nodeserver
nodeserver
filesystem
web
with streams
readStream.pipe(writeStream)	
  
//file.pipe(response);
fs.read('filename',	
  function(data){	
  
	
  	
  response.end(data);	
  
})
modules
module.exports = function () {} 

!
all modules should
be a single function
var	
  fs	
  =	
  require('fs');	
  
fs.readFile('filename',	
  function(data){console.log(data)})
npm	
  install	
  express	
  -­‐-­‐save
{	
  
	
  	
  "name":"pkgname",	
  
	
  	
  "version":	
  "0.3.0",	
  
	
  	
  "author":	
  "Eldar	
  Djafarov	
  <djkojb@gmail.com>",	
  
	
  	
  "dependencies":{	
  
	
  	
  	
  	
  "express":"3.4.0"	
  
	
  	
  }	
  
}	
  
npm scripts
//use	
  npm	
  scripts	
  
{	
  
	
  	
  "scripts":{	
  
	
  	
  	
  	
  "start":"node	
  start.js",	
  
	
  	
  	
  	
  "test":"node	
  test.js",	
  
	
  	
  	
  	
  "build":"grunt	
  build",	
  
	
  	
  	
  	
  "build":"node	
  ./node_modules/grunt-­‐cli/.bin/grunt	
  build"	
  
	
  	
  }	
  
}	
  
	
  	
  
$	
  npm	
  start	
  //	
  starts	
  an	
  app	
  
$	
  npm	
  test	
  //	
  runs	
  tests	
  
$	
  npm	
  run	
  build	
  //	
  builds	
  an	
  app	
  
express deep dive
simple nodejs server

var	
  http	
  =	
  require('http');	
  
http.createServer(function	
  (req,	
  res)	
  {	
  
	
  	
  res.writeHead(200,	
  {'Content-­‐Type':	
  'text/plain'});	
  
	
  	
  res.end('Hello	
  Worldn');	
  
}).listen(1337,	
  '127.0.0.1');	
  
console.log('Server	
  running	
  at	
  http://127.0.0.1:1337/');	
  
simple express server

var	
  express	
  =	
  require('express');	
  
var	
  app	
  =	
  express();	
  
app.use(function	
  middleware(req,	
  res,	
  next){	
  
	
  	
  //	
  do	
  stuff	
  
	
  	
  next();	
  
});	
  
app.get('/',	
  function(req,	
  res,	
  next){	
  
	
  	
  res.end('Hello	
  Worldn');	
  
});	
  
app.listen(1337);	
  
opinionated top level app
architecture
SPA
REST
API
DB
Angularjs
or
backbone
node.js
express
mongoose
mongodb
express rendering
add engine

app.engine('jade',	
  require('jade').__express);	
  
app.engine('html',	
  require('ejs').renderFile);	
  
render templates

res.render('index',	
  function(err,	
  html){	
  
	
  	
  res.send(html);	
  
});	
  
	
  	
  
res.render('user',	
  {	
  name:	
  'Tobi'	
  },	
  function(err,	
  html){	
  
	
  	
  res.send(html);	
  
});	
  
express deep dive
middleware concept

function	
  middleware(req,	
  res,	
  next){	
  	
  	
  
	
  	
  doAsyncStuff(asyncStuffDone);	
  
	
  	
  function	
  asyncStuffDone(err,	
  data){	
  
	
  	
  	
  	
  if(err){	
  
	
  	
  	
  	
  	
  	
  next(err);	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  next();	
  
	
  	
  }	
  
}	
  
middleware
middleware
middleware
middleware
request
response
express deep dive
middleware concept

request middleware
middleware
middleware
middleware
app.router
GET /
POST /profile
middleware
middleware
middleware
middleware
middleware
middleware
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(express.router)	
  
app.get('/',	
  middleware,	
  middleware,...,middleware)	
  
app.post('/profile',	
  middleware,	
  middleware,...,middleware)	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
express deep dive
middleware concept

request middleware
static
middleware
middleware
app.router
GET /
POST /profile
middleware
middleware
middleware
middleware
middleware
middleware
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(express.router)	
  
app.get('/',	
  middleware,	
  middleware,...,middleware)	
  
app.post('/profile',	
  middleware,	
  middleware,...,middleware)	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
!
app.use(express.static('./public'));	
  
!
app.use(middleware);
app.use(middleware);	
  
!
app.use('/static',express.static('./public'));	
  
!
app.use(middleware);
or	
  serve	
  public	
  with	
  /static
express deep dive
middleware concept

request middleware
middleware
middleware
middleware
app.router
GET /
POST /profile
middleware
middleware
middleware
middleware
middleware
error
middleware
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(express.router)	
  
app.get('/',	
  middleware,	
  middleware,...,middleware)	
  
app.post('/profile',	
  middleware,	
  middleware,...,middleware)	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
module.exports	
  =	
  function(err,	
  req,	
  res,	
  next){	
  
	
  	
  if(err){	
  
	
  	
  	
  	
  if(err.isError){	
  
	
  	
  	
  	
  	
  	
  return	
  res.json(err.code,	
  {err.reason});	
  
	
  	
  	
  	
  }	
  
	
  	
  }	
  
	
  	
  res.json(500,	
  {	
  
	
  	
  	
  	
  message:	
  'Something	
  is	
  terribly	
  wrong'	
  
	
  	
  });	
  
}	
  
express deep dive
middleware concept

request middleware
middleware
auth middle
middleware
app.router
GET /
POST /profile
middleware
middleware
middleware
middleware
middleware
middleware
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(express.router)	
  
app.get('/',	
  middleware,	
  middleware,...,middleware)	
  
app.post('/profile',	
  middleware,	
  middleware,...,middleware)	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
authentication
function	
  authentication(req,	
  res,	
  next){	
  
	
  	
  getUserBySessionId(req.session.uid,	
  gotUser);	
  
	
  	
  function	
  gotUser(err,	
  user){	
  
	
  	
  	
  	
  if(err)	
  return	
  next(err);	
  
	
  	
  	
  	
  if(!user){	
  
	
  	
  	
  	
  	
  	
  req.user	
  =	
  "guest";	
  
	
  	
  	
  	
  }else{	
  
	
  	
  	
  	
  	
  	
  req.user	
  =	
  user;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  next();	
  
	
  	
  }	
  
}	
  
express deep dive
middleware concept

request middleware
middleware
middleware
middleware
app.router
GET /
POST /profile
middleware
middleware
middleware
middleware
middleware
middleware
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(express.router)	
  
app.get('/',	
  middleware,	
  middleware,...,middleware)	
  
app.post('/profile',	
  middleware,	
  middleware,...,middleware)	
  
app.use(middleware);	
  
app.use(middleware);	
  
app.use(middleware);	
  
authorization
app.get('/user/:id',	
  userAccessOnly,	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  featureAccess('getUser'),	
  getUser);	
  
!
app.delete('/user/:id',	
  userAccessOnly,	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  featureAccess('deleteUser'),	
  deleteUser);	
  
!
app.put('/profile',	
  userAccessOnly,	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  featureAccess('editProfile'),	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  validateProfile,	
  editProfile);	
  
if(!req.user.features[feature]){	
  
	
  	
  return	
  next(err.notAutorized())	
  
}	
  
if(!req.user){	
  
	
  	
  return	
  next(err.noAuth());	
  
}	
  
next();	
  
var	
  uid	
  =	
  req.param('id');	
  
Users.delete(uid,	
  userGone);	
  
function	
  userGone(err){	
  
	
  	
  if(err)	
  next(err);	
  
	
  	
  res.json({message:"OK"});	
  
}	
  
testing Use mocha + chai + request
describe("User	
  passes	
  authentication",	
  function(){	
  
	
  	
  before(function(done){	
  
	
  	
  	
  	
  request.post('/api/auth',	
  {form:{login:login,	
  pwd:password}},	
  authDone);	
  
	
  	
  	
  	
  function	
  authDone(err,	
  response,	
  body){	
  
	
  	
  	
  	
  	
  	
  expect(response).to.have.property('statusCode',	
  200);	
  
	
  	
  	
  	
  	
  	
  done();	
  
	
  	
  	
  	
  }	
  
	
  	
  })	
  
	
  	
  describe("GET	
  /api/users	
  tries	
  to	
  get	
  all	
  users",	
  function(){	
  
	
  	
  	
  	
  var	
  users;	
  
	
  	
  	
  	
  before(function(done){	
  
	
  	
  	
  	
  	
  	
  request.get('/api/users',	
  gotUsers);	
  
	
  	
  	
  	
  	
  	
  function	
  gotUsers(err,	
  response,	
  data){	
  
	
  	
  	
  	
  	
  	
  	
  	
  users	
  =	
  data;	
  
	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  })	
  
	
  	
  	
  	
  it('returned	
  data	
  should	
  be	
  json',	
  function(){	
  
	
  	
  	
  	
  	
  	
  users	
  =	
  JSON.parse(users);	
  
	
  	
  	
  	
  	
  	
  expect(users).to.be.an('object');	
  
	
  	
  	
  	
  });	
  
	
  	
  	
  	
  it('there	
  should	
  be	
  >	
  5	
  users',	
  function(){	
  
	
  	
  	
  	
  	
  	
  expect(users).to.have.length.above(5);	
  
	
  	
  	
  	
  })	
  
	
  	
  	
  	
  ...	
  
	
  	
  })	
  
})
RESTful webservices
Resources are nouns
HTTP request types are verbs

resource
POST
create
GET
read
PUT
update
DELETE
delete
/dogs
create new
dog
list dogs
bulk update
dogs
bulk
remove
dogs
/dogs/:id error read dog
update dog
if exists
else error
delete dog
GET /dogs?color=red&state=running&location=park
Complex stuff optional after ‘?’ sign

bitly.com/restfulApi
environment
Use flation/nconf module
var	
  APP_ENV	
  =	
  process.env.APP_ENV||'development';	
  
nconf	
  =	
  require('nconf');	
  
nconf.argv()	
  
	
  	
  	
  	
  	
  .env()	
  
	
  	
  	
  	
  	
  .file({file:'./config/'+APP_ENV+'.config.json'});	
  
	
  	
  
nconf.get('app:host');	
  
nconf.get('app:port');	
  
nconf.get('security:salt');	
  
Q&A
СЛАВА УКРАЇНІ!
@edjafarov	

eldar.djafarov.com

node.js practical guide to serverside javascript

  • 1.
    node.js practical guide tojavascript on server
  • 2.
  • 3.
  • 4.
    single threaded/non blocking OS thread f()f() f() f() f() iocall1 iocall2 callback1 callback2
  • 5.
    heavy functions blockserver node worker worker worker worker so
  • 6.
    what you shouldn'tdo with node? • real real time :) • data bending
  • 7.
    without streams filesystem web nodeserver nodeserver filesystem web with streams readStream.pipe(writeStream)   //file.pipe(response); fs.read('filename',  function(data){      response.end(data);   })
  • 8.
    modules module.exports = function() {} ! all modules should be a single function var  fs  =  require('fs');   fs.readFile('filename',  function(data){console.log(data)}) npm  install  express  -­‐-­‐save {      "name":"pkgname",      "version":  "0.3.0",      "author":  "Eldar  Djafarov  <djkojb@gmail.com>",      "dependencies":{          "express":"3.4.0"      }   }  
  • 9.
    npm scripts //use  npm  scripts   {      "scripts":{          "start":"node  start.js",          "test":"node  test.js",          "build":"grunt  build",          "build":"node  ./node_modules/grunt-­‐cli/.bin/grunt  build"      }   }       $  npm  start  //  starts  an  app   $  npm  test  //  runs  tests   $  npm  run  build  //  builds  an  app  
  • 10.
    express deep dive simplenodejs server
 var  http  =  require('http');   http.createServer(function  (req,  res)  {      res.writeHead(200,  {'Content-­‐Type':  'text/plain'});      res.end('Hello  Worldn');   }).listen(1337,  '127.0.0.1');   console.log('Server  running  at  http://127.0.0.1:1337/');   simple express server
 var  express  =  require('express');   var  app  =  express();   app.use(function  middleware(req,  res,  next){      //  do  stuff      next();   });   app.get('/',  function(req,  res,  next){      res.end('Hello  Worldn');   });   app.listen(1337);  
  • 11.
    opinionated top levelapp architecture SPA REST API DB Angularjs or backbone node.js express mongoose mongodb
  • 12.
    express rendering add engine
 app.engine('jade',  require('jade').__express);   app.engine('html',  require('ejs').renderFile);   render templates
 res.render('index',  function(err,  html){      res.send(html);   });       res.render('user',  {  name:  'Tobi'  },  function(err,  html){      res.send(html);   });  
  • 13.
    express deep dive middlewareconcept
 function  middleware(req,  res,  next){          doAsyncStuff(asyncStuffDone);      function  asyncStuffDone(err,  data){          if(err){              next(err);          }          next();      }   }   middleware middleware middleware middleware request response
  • 14.
    express deep dive middlewareconcept
 request middleware middleware middleware middleware app.router GET / POST /profile middleware middleware middleware middleware middleware middleware app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(express.router)   app.get('/',  middleware,  middleware,...,middleware)   app.post('/profile',  middleware,  middleware,...,middleware)   app.use(middleware);   app.use(middleware);   app.use(middleware);  
  • 15.
    express deep dive middlewareconcept
 request middleware static middleware middleware app.router GET / POST /profile middleware middleware middleware middleware middleware middleware app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(express.router)   app.get('/',  middleware,  middleware,...,middleware)   app.post('/profile',  middleware,  middleware,...,middleware)   app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(middleware);   ! app.use(express.static('./public'));   ! app.use(middleware); app.use(middleware);   ! app.use('/static',express.static('./public'));   ! app.use(middleware); or  serve  public  with  /static
  • 16.
    express deep dive middlewareconcept
 request middleware middleware middleware middleware app.router GET / POST /profile middleware middleware middleware middleware middleware error middleware app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(express.router)   app.get('/',  middleware,  middleware,...,middleware)   app.post('/profile',  middleware,  middleware,...,middleware)   app.use(middleware);   app.use(middleware);   app.use(middleware);   module.exports  =  function(err,  req,  res,  next){      if(err){          if(err.isError){              return  res.json(err.code,  {err.reason});          }      }      res.json(500,  {          message:  'Something  is  terribly  wrong'      });   }  
  • 17.
    express deep dive middlewareconcept
 request middleware middleware auth middle middleware app.router GET / POST /profile middleware middleware middleware middleware middleware middleware app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(express.router)   app.get('/',  middleware,  middleware,...,middleware)   app.post('/profile',  middleware,  middleware,...,middleware)   app.use(middleware);   app.use(middleware);   app.use(middleware);   authentication function  authentication(req,  res,  next){      getUserBySessionId(req.session.uid,  gotUser);      function  gotUser(err,  user){          if(err)  return  next(err);          if(!user){              req.user  =  "guest";          }else{              req.user  =  user;          }          next();      }   }  
  • 18.
    express deep dive middlewareconcept
 request middleware middleware middleware middleware app.router GET / POST /profile middleware middleware middleware middleware middleware middleware app.use(middleware);   app.use(middleware);   app.use(middleware);   app.use(express.router)   app.get('/',  middleware,  middleware,...,middleware)   app.post('/profile',  middleware,  middleware,...,middleware)   app.use(middleware);   app.use(middleware);   app.use(middleware);   authorization app.get('/user/:id',  userAccessOnly,                    featureAccess('getUser'),  getUser);   ! app.delete('/user/:id',  userAccessOnly,                    featureAccess('deleteUser'),  deleteUser);   ! app.put('/profile',  userAccessOnly,                    featureAccess('editProfile'),                    validateProfile,  editProfile);   if(!req.user.features[feature]){      return  next(err.notAutorized())   }   if(!req.user){      return  next(err.noAuth());   }   next();   var  uid  =  req.param('id');   Users.delete(uid,  userGone);   function  userGone(err){      if(err)  next(err);      res.json({message:"OK"});   }  
  • 19.
    testing Use mocha+ chai + request describe("User  passes  authentication",  function(){      before(function(done){          request.post('/api/auth',  {form:{login:login,  pwd:password}},  authDone);          function  authDone(err,  response,  body){              expect(response).to.have.property('statusCode',  200);              done();          }      })      describe("GET  /api/users  tries  to  get  all  users",  function(){          var  users;          before(function(done){              request.get('/api/users',  gotUsers);              function  gotUsers(err,  response,  data){                  users  =  data;              }          })          it('returned  data  should  be  json',  function(){              users  =  JSON.parse(users);              expect(users).to.be.an('object');          });          it('there  should  be  >  5  users',  function(){              expect(users).to.have.length.above(5);          })          ...      })   })
  • 20.
    RESTful webservices Resources arenouns HTTP request types are verbs
 resource POST create GET read PUT update DELETE delete /dogs create new dog list dogs bulk update dogs bulk remove dogs /dogs/:id error read dog update dog if exists else error delete dog GET /dogs?color=red&state=running&location=park Complex stuff optional after ‘?’ sign
 bitly.com/restfulApi
  • 21.
    environment Use flation/nconf module var  APP_ENV  =  process.env.APP_ENV||'development';   nconf  =  require('nconf');   nconf.argv()            .env()            .file({file:'./config/'+APP_ENV+'.config.json'});       nconf.get('app:host');   nconf.get('app:port');   nconf.get('security:salt');  
  • 22.