node.js practical guide to serverside javascript
TRANSCRIPT
node.js
practical guide to javascript on server
javascript fast/memory suck:(
node
V8
libuvOS
single threaded/non blocking
OS
threadf() f() f() f() f()
io c
all 1
io c
all 2
callb
ack
1
callb
ack
2
heavy functions block server
node
worker worker worker worker
so
what you shouldn't do with node?
• real real time :)
• data bending
without streamsfilesystem
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 <[email protected]>", "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 divesimple nodejs server
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-‐Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/');
simple express servervar 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 World\n'); }); app.listen(1337);
opinionated top level app architecture
SPAREST
APIDB
Angularjs or
backbonenode.js express
mongoose
mongodb
express rendering add engine
app.engine('jade', require('jade').__express); app.engine('html', require('ejs').renderFile);
render templatesres.render('index', function(err, html){ res.send(html); }); res.render('user', { name: 'Tobi' }, function(err, html){ res.send(html); });
express deep divemiddleware concept
function middleware(req, res, next){ doAsyncStuff(asyncStuffDone); function asyncStuffDone(err, data){ if(err){ next(err); } next(); } }
middleware
middleware
middleware
middlewarerequest
response
express deep divemiddleware 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 divemiddleware 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 divemiddleware 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 divemiddleware 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);
authenticationfunction 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 divemiddleware 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 + requestdescribe("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 webservicesResources are nouns HTTP request types are verbs
resourcePOST create
GET read
PUT update
DELETE delete
/dogscreate new
doglist dogs
bulk update dogs
bulk remove dogs
/dogs/:id error read dogupdate dog
if exists else error
delete dog
GET /dogs?color=red&state=running&location=park
Complex stuff optional after ‘?’ sign bitly.com/restfulApi
environmentUse 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');