Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing RESTful web services using Node.js - Fr...

Writing RESTful web services using Node.js - Frontend Dev Conf 2013, Minsk

An introduction to node.js, using it to build a simple restful webservice. Talk given 2013-04-20.

Jakob Mattsson

April 20, 2013
Tweet

More Decks by Jakob Mattsson

Other Decks in Programming

Transcript

  1. Quick and easy customer feedback Touch&Tell helps you find out

    what your guests really think about your establishment or event. You ask questions, they answer. It’s that simple.
  2. From zero to: - Getting a server up and running

    - Getting, storing and updating data - Declaring the service interface - Authenticating the user
  3. Node.js is a platform built on Chrome's JavaScript runtime for

    easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
  4. Node.js is a platform built on Chrome's JavaScript runtime for

    easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
  5. http = require('http') onRequest = (req, res) -> res.writeHead(200, {

    'Content-Type': 'text/plain' }) res.end('Hello World\n') http.createServer(onRequest).listen(1337)
  6. npm

  7. npm is a package manager for node. You can use

    it to install and publish your node programs. ”It manages dependencies and does other cool stuff.”
  8. Connect is a midleware framework for node. It’s shipping with

    over 18 bundled middleware. It has a rich selection of 3rd-party middleware.
  9. connect = require('connect') app = connect() app.listen(3000) // last line

    equivalent to // http.createServer(app).listen(3000);
  10. connect = require('connect') app = connect() app.use connect.basicAuth (user, pass)

    -> return user == 'jakob' && pass == 'fdc13' app.use (req, res) -> res.writeHead(200, { 'Content-Type': 'text/plain' }) res.end('Hello World\n') app.listen(3000)
  11. logger csrf compress basicAuth bodyParser json urlencoded multipart cookieParser session

    cookieSession methodOverride responseTime staticCache static directory vhost favicon limit query errorHandler Request logger with custom format support Cross-site request forgery protection Gzip compression middleware Basic http authentication Extensible request body parser Application/json parser Application/x-www-form-urlencoded parser Multipart/form-data parser Cookie parser Session management support with bundled MemoryStore Cookie-based session support Faux HTTP method support Calculates response-time and exposes via X-Response-Time Memory cache layer for the static() middleware Streaming static file server supporting Range and more Directory listing middleware Virtual host sub-domain mapping middleware Efficient favicon server (with default icon) Limit the bytesize of request bodies Automatic querystring parser, populating req.query Flexible error handler
  12. express = require('express') app = express.createServer() app.get '/', (req, res)

    -> res.send('Hello World') app.get '/users/:id', (req, res) -> res.send('user ' + req.params.id) app.listen(3000)
  13. express = require('express') app = express.createServer() before1 = (req, res,

    next) -> req.foo = 'bar' next() before2 = (req, res, next) -> res.header('X-Time', new Date().getTime()) next() app.get '/', before1, (req, res) -> res.send('Hello World') app.get '/users/:id', [before1, before2], (req, res) -> console.log(req.foo) res.send('user ' + req.params.id) app.listen(3000)
  14. mongoose = require 'mongoose' mongoose.connect 'mongodb://localhost/tamblr' model = (name, schema)

    -> mongoose.model name, new mongoose.Schema schema, strict: true users = model 'users' name: type: String default: '' bio: type: String default: 'IE6-lover' age: type: Number default: null
  15. blogs = model 'blogs' name: type: String default: '' description:

    type: String default: '' users: type: ObjectId ref: 'users'
  16. posts = model 'posts' title: type: String default: '' body:

    type: String default: '' published: type: Date blogs: type: ObjectId ref: 'blogs'
  17. list = (model, callback) -> model.find {}, callback get =

    (model, id, callback) -> model.findById id, callback del = (model, id, callback) -> model.remove { _id: id }, callback put = (model, id, data, callback) -> model.update { _id: id }, data, { multi: false }, callback post = (model, data, callback) -> new model(data).save callback
  18. POST /users GET /users GET /users/42 DELETE /users/42 PUT /users/42

    POST /blogs GET /blogs GET /blogs/42 DELETE /blogs/42 PUT /blogs/42 POST /posts GET /posts GET /posts/42 DELETE /posts/42 PUT /posts/42
  19. models = [users, blogs, posts] Object.keys(models).forEach (modelName) -> app.get "/#{modelName}",

    (req, res) -> list models[modelName], (err, data) -> res.json data app.get "/#{modelName}/:id", (req, res) -> get models[modelName], req.params.id, (err, data) -> res.json data app.post "/#{modelName}", (req, res) -> post models[modelName], req.body, (err, data) -> res.json data app.del "/#{modelName}/:id", (req, res) -> del models[modelName], req.parmas.id, (err, count) -> res.json { count: count } app.put "/#{modelName}/:id", (req, res) -> put models[modelName], req.params.id, req.body, (err, count) -> res.json { count: count }
  20. POST /users GET /users GET /users/42 DELETE /users/42 PUT /users/42

    POST /blogs GET /blogs GET /blogs/42 DELETE /blogs/42 PUT /blogs/42 POST /posts GET /posts GET /posts/42 DELETE /posts/42 PUT /posts/42
  21. paths = models[modelName].schema.paths owners = Object.keys(paths).filter (p) -> paths[p].options.type ==

    ObjectId && typeof paths[p].options.ref == 'string' .map (x) -> paths[x].options.ref owners.forEach (owner) -> app.get "/#{owner}/:id/#{name}", (req, res) -> listSub models[name], owner, req.params.id, (err, data) -> res.json data app.post "/#{owner}/:id/#{name}", (req, res) -> postSub models[name], req.body, owner, req.params.id, (err, data) -> res.json data
  22. passport = require('passport') passportLocal = require('passport-local') passport.use new passportLocal.Strategy (user,

    pass, done) -> findUserPlz { username: user, password: pass }, (err, user) -> done(err, user) app.use(passport.initialize()) app.use(passport.authenticate('local'))
  23. passport = require('passport') twitter = require('passport-twitter') keys = { consumerKey:

    TWITTER_CONSUMER_KEY consumerSecret: TWITTER_CONSUMER_SECRET callbackURL: "http://127.0.0.1:3000/auth/twitter/callback" } passport.use new twitter.Strategy keys, (t, ts, profile, done) -> findOrCreateUserPlz { twitterId: profile.id }, (err, user) -> done(err, user) app.use(passport.initialize()) app.use(passport.authenticate('twitter'))
  24. ALL CHARACTERS AND EVENTS IN THIS SHOW-- EVENT THOSE BASED

    ON REAL PEOPLE--ARE ENTIRELY FICTIONAL. ALL CELEBERTY VOICES ARE IMPERSONATED.....POORLY. THE FOLLOWING PROGRAM CONTAINS COARSE LANGUAGE AND DUE TO ITS CONTENT IT SHOULD NOT BE VIEWED BE ANYONE