express node js

28
Kickstart NodeJS Yashprit Singh @yashprit

Upload: yashprit-singh

Post on 15-Jan-2015

510 views

Category:

Technology


1 download

DESCRIPTION

 

TRANSCRIPT

Kickstart NodeJS

Yashprit Singh@yashprit

Agenda

1. Middleware Concept2. Connect Middleware with Example3. Express Middleware.4. Express Philosophy.5. Express Cool Features.

What is Middleware in NodeJS ?

The middleware is called as a chain of functions, with order based on middleware definition order(time) with matching routes (if applicable).

e.g. req and res objects are travelling through chain so you can reuse/improve/modify data in them along the chain.

/* This is only for demonstration purpose*/function(req, res, next) {

req.name = “samething”; next(/* err and/or output */)}

Middleware cont.

This is sometime also called as Pipelines. Pipelines are everywhere, under various forms, uses and purposes. Generically, a Pipeline is a series of processing units connected together, where the output of one unit is the input for the next one. (In Node.js, this often means a series of functions in the form.)

If your middleware should return a response, just do so. If it shouldn't, it's implied that some later middleware should return a response. If you need to pass along data to that later part of the process, you should attach it to an appropriate part of the request object req.

P.S. Don’t confuse here about pipe(), thats belongs to another hero streams, streams are better suited to process flowing data

Middleware cont.

For example,

1. The bundled bodyParser middleware is responsible for populating req.rawBody and req.body based on the contents of the request body.

2. The bundled basicAuth middleware populates req.remoteUser based on the HTTP authentication.

Middleware Cont.

Two general use cases for middleware :-● Generic :- it will apply to every single request. Each middleware have to call

next() inside, if it wants to proceed to next middleware.● Specific :- When you use app.get('/path', function(...) this actual function is

middleware as well, just inline defined

The chain order is based on definition order. So it is important to define middleware in sync manner or order-reliable async manner. Otherwise different order of middleware can break logic.

Middleware : Connect

● Node.js itself offers an HTTP module, whose createServer method returns an object that you can use to respond to HTTP requests.

● That object inherits the http.Server prototype.

Connect Middleware

From the README:

Connect is an extensible HTTP server framework for node, providing high performance "plugins" known as middleware.

More specifically, connect wraps the Server, ServerRequest, and ServerResponse objects of node.js' standard httpmodule, giving them a few nice extra features, one of which is allowing the Server object to use a stack of middleware.

Connect Middleware Framework

● Connect has 18 bundled middleware and a rich selection of 3rd-party middleware..

● That's why Connect describes itself as a "middleware framework," and is often analogized to Ruby's Rack.

Example : Creating Simple Middleware

function uselessMiddleware(req, res, next) { next()

}

A middleware can also signal an error by passing it as the first argument to next:

// A middleware that simply interrupts every requestfunction worseThanUselessMiddleware(req, res, next) { next("Hey are you busy?")}

When a middleware returns an error like this, all subsequent middleware will be skipped until connect can find an error handler.

Adding middleware stack for server

To add a middleware to the stack of middleware for a server, we use it like so:

connect = require('connect')stephen = connect.createServer()stephen.use(worseThanUselessMiddleware)

Finally, you can also specify a path prefix when adding a middleware, and the middleware will only be asked to handle requests that match the prefix:

connect = require('connect')bob = connect.createServer()bob.use('/attention', worseThanUselessMiddleware)

URL based authentication policy

function authenticateUrls(urls /* basicAuth args*/) { basicAuthArgs = Array.slice.call(arguments, 1) basicAuth = require('connect').basicAuth.apply(basicAuthArgs) function authenticate(req, res, next) { // Warning! assumes that urls is amenable to iteration for (var pattern in urls) { if (req.path.match(pattern)) { basicAuth(req, res, next) return } } next() } return authenticate}

Role base authorization

function authorizeUrls(urls, roles) {

function authorize(req, res, next) {

for (var pattern in urls) {

if (req.path.match(pattern)) {

for (var role in urls[pattern]) {

if (users[req.remoteUser].indexOf(role) < 0) {

next(new Error("unauthorized"))

return

}

}

}

}

next()

}

return authorize

}

Error handling

email = require('node_mailer')

function emailErrorNotifier(generic_opts, escalate) { function notifyViaEmail(err, req, res, next) { if (err) { var opts = { subject: "ERROR: " + err.constructor.name, body: err.stack, } opts.__proto__ = generic_opts email.send(opts, escalate) } next() }}

Putting it all together

private_urls = { '^/attention': ['coworker', 'girlfriend'], '^/bank_balance': ['me'],}roles = { stephen: ['me'], erin: ['girlfriend'], judd: ['coworker'], bob: ['coworker'],}passwords = { me: 'doofus', erin: 'greatest', judd: 'daboss', bob: 'anachronistic discomBOBulation',}

function authCallback(name, password) { return passwords[name] === password

}stephen = require('connect').createServer()stephen.use(authenticateUrls(private_urls, authCallback))stephen.use(authorizeUrls(private_urls, roles))stephen.use('/attention', worseThanUselessMiddleware)stephen.use(emailErrorNotifier({to: '[email protected]'}))stephen.use('/bank_balance', function (req, res, next) { res.end("Don't be Seb-ish")})stephen.use('/', function (req, res, next) { res.end("I'm out of coffee")})

List of common uses connect middlewares

● logger request logger with custom format

support

● csrf Cross-site request forgery protection

● compress Gzip compression middleware

● basicAuth basic http authentication

● bodyParser extensible request body parser

● json application/json parser

● multipart multipart/form-data parser

● timeout request timeouts

● cookieParser cookie parser

● session session management support with

bundled MemoryStore

● cookieSession cookie-based session support

● methodOverride faux HTTP method support

● favicon efficient favicon server (with default

icon)

● query automatic querystring parser, populating

req.query

● errorHandler flexible error handler

Middleware: Express

Express does to Connect what Connect does to the http module: It offers a createServer method that extends Connect's Server prototype. So all of the functionality of Connect is there,plus view rendering and a handy DSL for describing routes. Ruby's Sinatra is a good analogy.

Philosophy behind ExpressJS

This is probably one of the most popular frameworks in the Node.js community of coders right now. The core philosophy behind ExpressJS is to offer an application framework for single or multi-page web apps, using views and template engine. The Express.js framework also includes a multitude of utilities to work with HTTP and building APIs. The pluggable middleware in the framework provides a great way to add elements, such as passportjs, as you need them.

Cool feature 1: routing

Routing is a way to map different requests to specific handlers.

var express = require("express");var http = require("http");var app = express();

app.all("*", function(request, response, next) { response.writeHead(200, { "Content-Type": "text/plain" }); next();});

app.get("/", function(request, response) { response.end("Welcome to the homepage!");});

app.get("/about", function(request, response) { response.end("Welcome to the about page!");});

app.get("*", function(request, response) { response.end("404!");});

http.createServer(app).listen(1337);

Cool feature 2: request handling

Express augments the request and response objects that you're passed in every request handler.response.redirect("/hello/anime");response.redirect("http://www.myanimelist.net");response.redirect(301, "http://www.anime.org"); // HTTP status code 301

This isn't in vanilla Node and it's also absent from Connect, but Express adds this stuff. It adds things like sendFile which lets you just send a whole file:

response.sendFile("/path/to/anime.mp4");

The request gets a number of cool properties, like request.ip to get the IP address and request.files to get uploaded files.

Cool feature 3: views

More features? Oh, Express, I'm blushing.Express can handle views. It's not too bad. Here's what the setup looks like:

// Start Expressvar express = require("express");var app = express();

// Set the view directory to /viewsapp.set("views", __dirname + "/views");

// Let's use the Jade templating languageapp.set("view engine", "jade");

The first block is the same as always. Then we say "our views are in a folder called 'views'".

Bonus cool feature: everything from Connect and Node

I want to remind you that Express is built on top of Connect which is built on top of Node. This means that all Connect middleware works with Express. This is useful! For example:

var express = require("express");var app = express();

app.use(express.logger()); // Inherited from Connect

app.get("/", function(req, res) { res.send("anime");});

app.listen(1337);

Folder Structure : My Preference

/public

/images (there are several images exported from Photoshop)

/javascripts

/stylesheets

/style.css

/style.less (imports home.less and inner.less)

/routes

/index.js

/app

/views

/index.ejs (home page)

/inner.ejs (template for every other page of the site)

/controller/model

/app.js

/package.json

Q-A

Thank You@yashprit

MVC in Express

var express = require('express');

,app = express()

,fs = require('fs')

// database connection

var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/mydb');

// some environment variables

app.set('port', process.env.PORT || 3000);

app.set('views', __dirname + '/views');

app.set('view engine', 'ejs');

app.use(app.router);

app.use(express.static(path.join(__dirname,

'public')));

// dynamically include routes (Controller)

fs.readdirSync('./controllers').forEach(function

(file) {

if(file.substr(-3) == '.js') {

route = require('./controllers/' + file);

route.controller(app);

}

});

http.createServer(app).listen(app.get('port'),

function(){

console.log('Express server listening on port ' +

app.get('port'));

});

NodeJS HTTP AbstractionExpress wonderfull middlewarePhilosophy behind ExpressJSMVC in NodeJS

http://evanhahn.com/understanding-express/

NodeJS HTTP Abstraction

http://stackoverflow.com/questions/5284340/what-is-node-js-connect-express-and-middlewarehttp://expressjs.com/guide.htmlhttps://github.com/senchalabs/connecthttp://stackoverflow.com/questions/17750308/middleware-design-pattern-in-node-js-connecthttp://expressjs.com/2x/guide.html#middlewarehttp://stackoverflow.com/questions/6893876/nodejs-and-connect-next-functionalityhttp://www.mariocasciaro.me/the-strange-world-of-node-js-design-patternshttp://philsversion.com/2011/08/24/lessons-learnt-from-my-first-node-js-project/http://stella.laurenzo.org/2011/03/bulletproof-node-js-coding/

http://code.tutsplus.com/tutorials/meet-the-connect-framework--net-31220

http://stephensugden.com/middleware_guide/

http://howtonode.org/connect-it