Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Building your first Node app with Connect & Express

33,300 views

Published on

Talk given at JS-Montreal #10.

Published in: Technology
  • Be the first to comment

Building your first Node app with Connect & Express

  1. 1. Building your first Node app with Connect & Express Christian Joudrey - @cjoudrey
  2. 2. Getting Started <ul><ul><li>Node.js: http://nodejs.org/#download </li></ul></ul><ul><ul><li>npm, a package manager for Node: curl http://npmjs.org/install.sh | sh </li></ul></ul><ul><ul><li>Use npm to install Connect and Express for Node: npm install connect && npm install express </li></ul></ul><ul><ul><li>Many more modules at: http://npm.mape.me/ </li></ul></ul>
  3. 3. Hello World in Node.js <ul><li>// Load the http module </li></ul><ul><li>var http = require(' http '); </li></ul><ul><li>// Setup a HTTP server, listen on port 8080 </li></ul><ul><li>http.createServer(function (req, res) { </li></ul><ul><li>   res.writeHead(200, { </li></ul><ul><li>     ' Content-Type ': ' text/plain ' </li></ul><ul><li>   }); </li></ul><ul><li>   res.end(' Hello World '); </li></ul><ul><li>}).listen(8080, ' 127.0.0.1 '); </li></ul>
  4. 4. Node's HTTP module <ul><ul><li>Very low level. </li></ul></ul><ul><ul><li>No cookie handling or parsing. </li></ul></ul><ul><ul><li>No session support built-in. </li></ul></ul><ul><ul><li>No routing built-in. </li></ul></ul><ul><ul><li>No static file serving. </li></ul></ul>
  5. 5. Connect makes it easier <ul><ul><li>Static File Server </li></ul></ul><ul><ul><li>Body Decoder </li></ul></ul><ul><ul><li>Cookie Decoder </li></ul></ul><ul><ul><li>Session Provider </li></ul></ul><ul><ul><li>Request Router </li></ul></ul><ul><ul><li>Logs </li></ul></ul><ul><ul><li>Sass/Less Compiler </li></ul></ul><ul><ul><li>Virtual Host Router </li></ul></ul>
  6. 6. ...but, you decide what blocks you want.
  7. 7. Hello World in Connect <ul><li>// Load the connect module </li></ul><ul><li>var  connect = require(' connect '); </li></ul><ul><li>// Setup a HTTP server, listen on port 8080 </li></ul><ul><li>connect.createServer(function (req, res) { </li></ul><ul><li>   res.writeHead(200, { </li></ul><ul><li>     ' Content-Type ': ' text/plain ' </li></ul><ul><li>   }); </li></ul><ul><li>   res.end(' Hello World '); </li></ul><ul><li>}).listen(8080, ' 127.0.0.1 '); </li></ul>
  8. 8. .use() and next() <ul><li>var  connect = require(' connect '); </li></ul><ul><li>var s = connect.createServer(); </li></ul><ul><li>s.use(function (req, res, next) { </li></ul><ul><li>   // Send to next handler if url not /about </li></ul><ul><li>   if (req.url != ' /about ') return next(); </li></ul><ul><li>   res.end(' About page '); </li></ul><ul><li>}); </li></ul><ul><li>s.use(function (req, res, next) { </li></ul><ul><li>   res.end(' Default page '); </li></ul><ul><li>}); </li></ul><ul><li>s.listen(8080, ' 127.0.0.1 '); </li></ul>
  9. 9. Routing Middleware <ul><li>s.use(connect.router(function(app) { </li></ul><ul><li>   app.get(' /users ', function(req, res, next) { </li></ul><ul><li>     res.end(' List users '); </li></ul><ul><li>   }); </li></ul><ul><li>   app.post(' /users ', function(req, res, next) { </li></ul><ul><li>     res.end(' Create a new user '); </li></ul><ul><li>   }); </li></ul><ul><li>   app.get(' /user/:id ', function(req, res, next) { </li></ul><ul><li>     if (!is_admin(req)) { </li></ul><ul><li>       return next( new Error(' access denied ')); </li></ul><ul><li>     } </li></ul><ul><li>     res.end(' Edit user ' + req.params.id); </li></ul><ul><li>   }); </li></ul><ul><li>})); </li></ul><ul><li>s.use(function(err, req, res, next) { </li></ul><ul><li>   res.end(err.message); </li></ul><ul><li>}); </li></ul>
  10. 10. Full example with Connect <ul><li>var connect = require(' connect '); </li></ul><ul><li>var s = connect.createServer(); </li></ul><ul><li>s.use(connect.logger()); </li></ul><ul><li>s.use(connect.favicon(__dirname + ' /static/favicon.ico ')); </li></ul><ul><li>s.use(connect.static(__dirname + ' /static ')); </li></ul><ul><li>s.use(connect.cookieParser()); // adds req.cookies </li></ul><ul><li>s.use(connect.bodyParser()); // adds req.body </li></ul><ul><li>s.use(connect.router(require(' ./users ')); </li></ul><ul><li>s.use(connect.router(require(' ./index ')); </li></ul><ul><li>s.use(function(err, req, res, next) { </li></ul><ul><li>   res.end(' Internal Server Error '); </li></ul><ul><li>}); </li></ul><ul><li>s.listen(8080, ' 127.0.0.1 '); </li></ul>
  11. 11. Express is even easier <ul><ul><li>Connect is easier than raw node.js, but still low level. </li></ul></ul><ul><ul><li>...but, it's good for simple RESTful API's </li></ul></ul><ul><ul><li>...or to make your own framework. </li></ul></ul><ul><ul><li>Express is a simple framework inspired by Sinatra (Ruby). </li></ul></ul><ul><ul><li>It's built on top of Connect. </li></ul></ul>
  12. 12. Hello World in Express <ul><li>var  express = require(' express '); </li></ul><ul><li>var  app = express.createServer(); </li></ul><ul><li>app.get(' / ', function(req, res) { </li></ul><ul><li>   res.send(' hello world '); </li></ul><ul><li>}); </li></ul><ul><li>app.listen(8080); </li></ul>
  13. 13. Getting Started with Express <ul><ul><li>Generate skeleton apps: express –help </li></ul></ul><ul><ul><li>Generate app with sessions and template engine: express --sessions --template ejs hello </li></ul></ul><ul><ul><li>Generated structure: $ ls hello/ app.js   logs    pids    public    test    views $ ls hello/views/ index.ejs  layout.ejs </li></ul></ul>
  14. 14. Configurations <ul><li>app.configure(function() { </li></ul><ul><li>   // Global configurations </li></ul><ul><li>   app.use(express.bodyParser()); // parse incoming data </li></ul><ul><li>   app.use(express.cookieParser()); // parse cookies </li></ul><ul><li>   app.use(express.session({ secret: ' your secret ' }); </li></ul><ul><li>}); </li></ul><ul><li>app.configure(' development ', function() { </li></ul><ul><li>   // Development configurations </li></ul><ul><li>   // i.e. Error handler to print errors and show stack? </li></ul><ul><li>}); </li></ul><ul><li>app.configure(' production ', function() { </li></ul><ul><li>   // Production configurations </li></ul><ul><li>}); </li></ul>Controlled by:        NODE_ENV=production node app.js
  15. 15. Routing <ul><li>app.get(' /users ', function(req, res) { </li></ul><ul><li>   // List user </li></ul><ul><li>}); </li></ul><ul><li>app.post(' /users ', function(req, res) { </li></ul><ul><li>   // Create user </li></ul><ul><li>   // req.body contains POST data </li></ul><ul><li>}); </li></ul><ul><li>app.get(' /user/:id ', function(req, res) { </li></ul><ul><li>   // Edit user </li></ul><ul><li>   // req.params.id contains value of :id param </li></ul><ul><li>}); </li></ul>
  16. 16. Sanitizing Route Params <ul><li>app.param(' :id ', function(v) { </li></ul><ul><li>   return parseInt(v, 10); </li></ul><ul><li>}); </li></ul><ul><li>app.get(' /user/:id ', function(req, res) { </li></ul><ul><li>   res.send(' user id: ' + req.params.id); </li></ul><ul><li>}); </li></ul>
  17. 17. Even better... <ul><li>var integer = function(v) { </li></ul><ul><li>   return  parseInt(v, 10); </li></ul><ul><li>}; </li></ul><ul><li>app.param(' :id ', integer); </li></ul><ul><li>app.get(' /user/:id ', function(req, res) { </li></ul><ul><li>   res.send(' user id:  ' + req.params.id); </li></ul><ul><li>}); </li></ul>
  18. 18. Route Param Pre-conditions <ul><li>app.get(' /user/:id ', function(req, res) { </li></ul><ul><li>   var id = req.params.id; </li></ul><ul><li>   User.get(id, function(err, user) { </li></ul><ul><li>     if (err) return next(err); </li></ul><ul><li>     res.send(' user ' + user.name); </li></ul><ul><li>   }); </li></ul><ul><li>}); </li></ul><ul><li>app.put(' /user/:id ', function(req, res) { </li></ul><ul><li>   var  id = req.params.userId; </li></ul><ul><li>   User.get(id, function(err, user) { </li></ul><ul><li>     if  (err)  return  next(err); </li></ul><ul><li>     user.update(req.body); </li></ul><ul><li>   }); </li></ul><ul><li>}); </li></ul>Same logic every time there is :id
  19. 19. Even better... <ul><li>var  loadUser = function(req, res, next) { </li></ul><ul><li>   var  id = req.params.id; </li></ul><ul><li>   User.get(id, function(err, user) { </li></ul><ul><li>     if  (err)  return  next(err); </li></ul><ul><li>     if  (!user)  return  next( new  Error(' invalid userId ')); </li></ul><ul><li>     req.user = user; </li></ul><ul><li>     next(); </li></ul><ul><li>   }); </li></ul><ul><li>}); </li></ul><ul><li>app.get(' /user/:id ', loadUser, function(req, res) { </li></ul><ul><li>   res.send(' user  ' + req.user.name); </li></ul><ul><li>}); </li></ul><ul><li>app.put(' /user/:id ', loadUser, function(req, res) { </li></ul><ul><li>   req.user.update(req.body); </li></ul><ul><li>}); </li></ul>
  20. 20. You can stack them... <ul><li>app.put(' /user/:id ', isAdmin, loadUser, function(req, res) { </li></ul><ul><li>   req.user.update(req.body); </li></ul><ul><li>}); </li></ul><ul><li>app.put(' /user/:id ', function(req, res, next) { </li></ul><ul><li>   // Verify if the current user is an admin </li></ul><ul><li>   isAdmin(req, res, function(err) { </li></ul><ul><li>     if  (err)  return  next(err); </li></ul><ul><li>     loadUser(req, res, function(err, user) { </li></ul><ul><li>       if  (err)  return  next(err); </li></ul><ul><li>       req.user.update(req.body); </li></ul><ul><li>     }); </li></ul><ul><li>   }); </li></ul><ul><li>}); </li></ul>...cleaner than...
  21. 21. Views <ul><ul><li>&quot;Built-in&quot; support for : </li></ul></ul><ul><ul><ul><li>Jade (Haml-like):  http://jade-lang.com/ </li></ul></ul></ul><ul><ul><ul><li>EJS (Embedded JS):  http://embeddedjs.com/ </li></ul></ul></ul><ul><ul><li>Support for partials. </li></ul></ul>
  22. 22. Rendering Views <ul><li>app.get(' /user/:id ', loadUser, function(req, res) { </li></ul><ul><li>   res.render(' user_edit ', { </li></ul><ul><li>     locals: { </li></ul><ul><li>       user: req.user, </li></ul><ul><li>       title: ' Edit User ' + req.user.username </li></ul><ul><li>     } </li></ul><ul><li>   }); </li></ul><ul><li>}); </li></ul>
  23. 23. Other useful functions... <ul><ul><li>app.helpers(Object) </li></ul></ul><ul><ul><ul><li>Set functions that are available in your views </li></ul></ul></ul><ul><ul><li>app.dynamicHelpers(Object) </li></ul></ul><ul><ul><ul><li>Set helpers that require the req and res objects </li></ul></ul></ul><ul><ul><li>app.error(Function), called when: </li></ul></ul><ul><ul><ul><li>throw new Error() </li></ul></ul></ul><ul><ul><ul><li>next(new Error()) </li></ul></ul></ul>
  24. 24. Interesting Links <ul><ul><li>Lots of Express examples:  http://bit.ly/ExpressExamples </li></ul></ul><ul><ul><li>Express Documentation:   http://bit.ly/ExpressDocs </li></ul></ul><ul><ul><li>Database wrappers and ORMs: </li></ul></ul><ul><ul><ul><li>Mongoose (MongoDB, ORM-like):  https://github.com/LearnBoost/mongoose </li></ul></ul></ul><ul><ul><ul><li>Cradle (CouchDB, HTTP wrapper): https://github.com/cloudhead/cradle </li></ul></ul></ul><ul><ul><ul><li>Couch-ar (CouchDB, Active Record implementation): https://github.com/scottburch/couch-ar </li></ul></ul></ul>
  25. 25. Questions? :)

×