Building your first Node app with Connect & Express

32,686 views

Published on

Talk given at JS-Montreal #10.

Published in: Technology
0 Comments
29 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
32,686
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
258
Comments
0
Likes
29
Embeds 0
No embeds

No notes for slide
  • - brief overview of what node has built in - overview of how to use Connect is - overview of how to use ExpressJS is - ask questions at any time
  • - Explain the basics of http module and createServer function. - req is object that has request stuff (url, get params, body, cookies, ..) - res is object that has response stuff (set headers, send data, ..)
  • - just a very simple http wrapper - gotta code everything up on your own
  • - connect makes it easier - comes with many useful bundles - typical functionalities that you will need
  • - similar to node's http module - if put all in same callback, can get messy
  • - use() is a different way of setting callbacks - we call them Middleware - behind use() is a stack, first in, first out - can use next() to trigger next handler - can have infinite handles
  • - a better way of setting routes - HTTP verbs - capture url params using colon - can also use regular expressions - next() Error handling - don't need to use next to pass to next() handler. - can organize by module
  • - stack the middlewares you want - called in order - seperate controllers into modules
  • - easier than node, but still low level - No view engine, gotta add your own - Configurations, on your own - good for restful since dont need view engine - express is like sinatra - built with connect - all the features of connect, but more
  • - try it out with CLI tool, its easy - multiple template engines (jade, ejs, mustache, etc...) - css compiler support (less, sass)
  • - configuration blocks - can be controlled with NODE_ENV environment variable
  • - Uses Connect.router - Can use HTTP verbs - Can capture params - req.body for POST - req.params for url params
  • - can sanitize parameters - force type on params - some cases in couchdb that you can nosql injections. this would prevent
  • - generalize formatters - reuseable
  • - we want to validate user exists in both situations - we aren't reusing the code - same logic every time
  • - you could also validate that the userId is an integer using same method. - and call next() if not int
  • - you can add as many as you need - this example, checking login and checking user exists
  • - built in ejs and jade - ejs is html with embedded JS - jade is like haml - partials, can render views inside a view
  • - automatically loads views/user_edit.jade - .render automatically includes layout.jade
  • - cant go through all of them, just so you know - app.helpers takes an object and exposes in views - app.dynamicHelpers when you want to use request vars - app error, 
  • Interesting Links
  • 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? :)

    ×