Upload
jguerrero999
View
208
Download
2
Embed Size (px)
Citation preview
NODE.JS ARCHITECTURE ANDGETTING STARTED WITH EXPRESS.JS
Jordan Kasper | Developer Evangelist
NODE.JS ARCHITECTURE
MODULARITY
MODULE PATTERNSThere are various patterns...
Simple Object APIRevealing Module (Function Initialization)Object Constructor
SIMPLE OBJECT API// lib/employee.jsmodule.exports = salary: 50000, giveRaise: function( amount ) salary += amount; ;
Why not always use simple objects?Modules are cached!
REVEALING MODULE PATTERNmodule.exports = function createWorker( options )
// Setup...
return salary: 50000, giveRaise: function( amount ) this.salary += amount; ;;
OBJECT CONSTRUCTOR PATTERNvar Worker = module.exports = function Worker( options ) // ...;
Worker.prototype.salary = 50000;Worker.prototype.giveRaise = function( amount ) this.salary += amount;;
SCALING
VERTICAL SCALING
NODE CLUSTERING
var http = require('http'), cluster = require('cluster');
if (cluster.isMaster)
for (var i = 0; i < numCPUCores; i++) cluster.fork(); ;
else
http .createServer(function(req, res) // ... ) .listen(8080, ...););
USING A PROCESS MANAGEREasy clustering and scaling without altering application
codeStrongLoop Process Manager (strong-pm)PM2
Comparison Chart
Forever
LOAD BALANCINGcluster uses a simple round-robin approach...
...but there are better ways!
HORIZONTAL SCALING
HORIZONTAL SCALING
BASIC NGINX CONFIGserver listen 80 location / proxy_pass http://localhost:3000;
location /static/ root /var/www/myapp/public;
$ sudo service nginx start
NGINX LOAD BALANCERhttp upstream myapp least_conn; # roundrobin is the default... # Or use ip_hash; for "sticky" sessions... server www1.myapp.com; server www2.myapp.com; server www3.myapp.com;
server listen 80 location / proxy_pass http://myapp;
STRONGLOOP AND NGINXIf you're using strong-pm you can use the
!StrongLoop nginx
controller~$ npm install g strongnginxcontroller
~$ slnginxctlinstall
Install the Controller on the load balancing host...
...then manage the load balancing infrastructure from:StrongLoop Arc
SCALING WITH STRONGLOOP ARC
EXPRESS.JS
EXPRESS.JSFast, light, unopinionated framework for web applications.
EXPRESS HELLO WORLD~/myapp$ npm init...
~/myapp$ npm install express save
EXPRESS HELLO WORLD// in app.jsvar express = require('express');var myApp = express();
myApp.get('/', function handleRoot(req, res, next) res.send('Hello World!'););
myApp.listen(8080);
~/myapp$ node app.js
SCAFFOLDING AN EXPRESS APP
SCAFFOLDING EXPRESSInstall the CLI generator first...
~$ npm install g expressgenerator
~$ express myapp...~$ cd myapp~/myapp$ npm install
A SCAFFOLDED APPmyapp/ |_ bin # execution file (shell script) |_ node_modules |_ public # images, css, fonts, etc |_ routes # Node.js routing code |_ views # serverside templates |_ app.js |_ package.json
RUNNING A SCAFFOLDED APP~/myapp$ npm start
..., "scripts": "start": "node ./bin/www" , ...
CONFIGURING EXPRESS
CONFIGURING EXPRESSvar app = express();
app.set('views', 'views');app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);app.set('foo', 'bar');
server.listen( app.get('port') );
REQUEST ROUTING
BASIC ROUTINGvar express = require('express');var myApp = express();
myApp.get('/', function handleRoot(req, res, next) res.send('Hello World!'););
myApp.listen( 3000 );
POST ROUTINGmyApp.post('/user', function createUser(req, res, next) // Create the user record...
res.redirect('/myaccount'););
POST ROUTINGmyApp.post('/user', function createUser(req, res, next) // Create the user record...
// Where do we get the data from?
res.redirect('/myaccount'););
MIDDLEWARE
MIDDLEWARE EXAMPLESvar express = require('express'), bodyParser = require('bodyparser');
var app = express();
// app config...
// Parse POST form data...app.use( bodyParser.urlencoded( extended: false ) );
app.post('/user', function createUser() var user = username: req.body.username, ... ; ...);
ORDER MATTERS!Middleware are executed in the order specified
app.use( express.logger('dev') );
app.use( myAuthModule() );
app.use( bodyParser.json() );
app.use(bodyParser.urlencoded( extended: false ));
app.use(express.static(path.join(__dirname, 'public')));
// Routing middleware...
MIDDLEWARE - WHEN DOES IT END?Middleware processing ends when next() is not called
(or an error is generated)app.use(bodyParser.json());app.use(bodyParser.urlencoded( extended: false ));
app.get('/about', function aboutUs(req, res, next)
res.send('We are StrongLoop!');
// no call to next());
app.get('/user', ...);
CUSTOM MIDDLEWAREapp.use(function (req, res, next) // Do some work...
// Modify the req or res...
// execute the callback when done next(););
CUSTOM MIDDLEWARE - ERRORSapp.use(function (req, res, next) // do something...
if (thereWasAnError) var err = new Error(' ... '); next( err ); return;
// No error, so we proceed...
next(););
HANDLING MIDDLEWARE ERRORSapp.use(function(err, req, res, next) // Do whatever you need to...
if (err.code === 404)
res.redirect('/error404');
else // Or you can keep processing this (or a new) Error next(err); );
HANDLING MIDDLEWARE ERRORSAlways set up a "catchall" error handler!
SERVER-SIDE TEMPLATING
TEMPLATESSmall blocks that we can plug data into at run-time
// /views/index.jadedoctype htmlhtml head title #title body section.mainbody.clear #homepageText
TEMPLATING ENGINE~/myapp$ npm install save jade
var app = express();
app.set('views', 'views');app.set('view engine', 'jade');
USING A TEMPLATEapp.get('/' function handleRoot(req, res, next)
res.render('index', title: 'StrongLoop Home', homepageText: 'We all love StrongLoop!' );
);
DON'T FORGET YOUR MODULARITY!
NOT MODULAR...var express = require('express'), bodyParser = require('bodyparser');
var app = express();
// app config and other middleware...
app.post('/user', function createUser() var user = username: req.body.username, ... ;
db.create(user, function() res.render('user/myaccount', ... ); ););
THE 4.0 ROUTER INTERFACE// in routes/users.jsvar express = require('express');var router = express.Router();
router.get('/', function(req, res, next) // Get a list of users... res.render('user/list', results: users ););
router.get('/:id', function(req, res, next) // Get a single user... res.render('user/myaccount', user: user ););
router.post('/', function(req, res, next) // Create a user... res.redirect('user/myaccount', user: user ););
module.exports = router;
THE 4.0 ROUTER INTERFACE// in app.jsvar express = require('express'), ...;
var app = express();
// app config and middleware...
app.use('/users', require('./routes/users'));
REQUEST OBJECT
QUERY PARAMETERSapp.get('/users', function (req, res, next)
var limit = req.query.limit || 10, users = [];
// Retrieve all users...
res.render('user/list', results: users, nextIndex: 11 ););
URL PARAMETERSapp.get('/users/:id', function (req, res, next)
var id = req.params.id, user = null;
// Retrieve a single user...
if (req.xhr) res.json( user: user ); else res.render('user/single', user: user ); );
URL PARAMETERSapp.get(/\/users\/(\d+)$/, function (req, res, next)
var id = req.params[0], user = null;
// Retrieve a single user... // ...);
RESPONSE OBJECT
RESPONSE METHODSresponse.send(data) or response.end(data)
response.status(httpStatus)
response.send(201, someData)
response.sendfile('path/to/someFile.json')
response.download('/report-12345.pdf')
HTTP STATUS CODES2XX: for successfully processed requests3XX: for redirections or cache information4XX: for client-side errors5XX: for server-side errors
QUESTIONS?NODE.JS ARCHITECTURE AND
GETTING STARTED WITH EXPRESS.JS
Jordan Kasper | Developer EvangelistJoin us for more events!
strongloop.com/developers/events