diff --git a/2x/applications.html b/2x/applications.html deleted file mode 100644 index 113485e8..00000000 --- a/2x/applications.html +++ /dev/null @@ -1,270 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- - - -
- - -

Learnboost is a free online gradebook application, aimed to crush the competition with innovative, realtime, enjoyable features.

- -

LearnBoost

- -

Storify lets you turn what people post on social media websites into compelling stories.

- -

Storify

- -

Pakistan Survey by Development Seed, provides in-depth agency-specific analysis from regional experts with data from 1,000 interviews across 120 villages in all seven tribal agencies and mapping of 142 reported drone strikes in FATA through July 2010.

- -

Pakistan Survey

- -

Markup.IO allows you to draw directly on any website, then share with others to share your thoughts.

- -

Markup.IO

- -

Scrabb.ly is a massively multiplayer scrabble game initially created for the Node Knockout competition.

- -

Online Realtime Scrabble

- -

ClickDummy is a rapid mockup prototyping application for designers and dummies.

- -

Mockup Prototying

- -

Node Knockout organized the first ever node-specific competition with hundreds of contestants.

- -

Node Knockout Competition Express

- -

Widescript is an innovative app that helps you focus and interact with your texts – on your desktop, your couch or on the go.

- -

Widescript

- -

e-resistable is an online order takeaway system providing an intuitive way to fill your belly from your computer!

- -

Online Takeaway

- -

Top Twitter Trends utilizes MongoDB, Socket.IO, jQuery and many other exciting libraries to bring you trending tweets in realtime.

- -

Twitter Trends

- -
- - -

The applications shown above are not listed in any specific order. To have an application added or removed please contact TJ Holowaychuk.

-
-
- - diff --git a/2x/applications.md b/2x/applications.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/applications.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/contrib.html b/2x/contrib.html deleted file mode 100644 index c457214e..00000000 --- a/2x/contrib.html +++ /dev/null @@ -1,264 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -

Development Dependencies

- -

First install the dev dependencies by executing the following command in the repo’s directory:

- -
$ npm install
-
- -

Running Tests

- -

Express uses the Expresso TDD -framework to write and run elegant test suites extremely fast. To run all test suites -simply execute:

- -
$ make test
-
- -

To target specific suites we may specify the files via:

- -
$ make test TESTS=test/view.test.js
-
- -

To check test coverage run:

- -
$ make test-cov
-
- -

Contributions

- -

To accept a contribution, you should follow these guidelines:

- - - - -

Documentation

- -

To contribute documentation edit the markdown files in ./docs, however -do not run make docs, as they will be re-built and published with each release.

-
-
- - diff --git a/2x/contrib.md b/2x/contrib.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/contrib.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/applications.html b/2x/docs/applications.html deleted file mode 100644 index ba84becc..00000000 --- a/2x/docs/applications.html +++ /dev/null @@ -1,246 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- - - -
- - -

Learnboost is a free online gradebook application, aimed to crush the competition with innovative, realtime, enjoyable features.

- -

LearnBoost

- -

Storify lets you turn what people post on social media websites into compelling stories.

- -

Storify

- -

Pakistan Survey by Development Seed, provides in-depth agency-specific analysis from regional experts with data from 1,000 interviews across 120 villages in all seven tribal agencies and mapping of 142 reported drone strikes in FATA through July 2010.

- -

Pakistan Survey

- -

Markup.IO allows you to draw directly on any website, then share with others to share your thoughts.

- -

Markup.IO

- -

Scrabb.ly is a massively multiplayer scrabble game initially created for the Node Knockout competition.

- -

Online Realtime Scrabble

- -

ClickDummy is a rapid mockup prototyping application for designers and dummies.

- -

Mockup Prototying

- -

Node Knockout organized the first ever node-specific competition with hundreds of contestants.

- -

Node Knockout Competition Express

- -

Widescript is an innovative app that helps you focus and interact with your texts – on your desktop, your couch or on the go.

- -

Widescript

- -

e-resistable is an online order takeaway system providing an intuitive way to fill your belly from your computer!

- -

Online Takeaway

- -

Top Twitter Trends utilizes MongoDB, Socket.IO, jQuery and many other exciting libraries to bring you trending tweets in realtime.

- -

Twitter Trends

- -
- - -

The applications shown above are not listed in any specific order. To have an application added or removed please contact TJ Holowaychuk.

-
-
- - diff --git a/2x/docs/applications.md b/2x/docs/applications.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/applications.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/contrib.html b/2x/docs/contrib.html deleted file mode 100644 index 0fad6ecf..00000000 --- a/2x/docs/contrib.html +++ /dev/null @@ -1,240 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -

Development Dependencies

- -

First install the dev dependencies by executing the following command in the repo’s directory:

- -
$ npm install
-
- -

Running Tests

- -

Express uses the Expresso TDD -framework to write and run elegant test suites extremely fast. To run all test suites -simply execute:

- -
$ make test
-
- -

To target specific suites we may specify the files via:

- -
$ make test TESTS=test/view.test.js
-
- -

To check test coverage run:

- -
$ make test-cov
-
- -

Contributions

- -

To accept a contribution, you should follow these guidelines:

- - - - -

Documentation

- -

To contribute documentation edit the markdown files in ./docs, however -do not run make docs, as they will be re-built and published with each release.

-
-
- - diff --git a/2x/docs/contrib.md b/2x/docs/contrib.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/contrib.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/executable.html b/2x/docs/executable.html deleted file mode 100644 index 805e9fae..00000000 --- a/2x/docs/executable.html +++ /dev/null @@ -1,216 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -

Synopsis

- -
express [options] [PATH]
-
- -

Description

- -

The express executable generates apps at the given PATH or the -current working directory. Although Express is not bound to a specific -application structure, this executable creates a maintainable base app.

- -

Options

- -
  -s, --sessions         Add session support
-  -t, --template ENGINE  Add template ENGINE support (jade|ejs). Defaults to jade
-  -c, --css ENGINE       Add stylesheet ENGINE support (less|sass|stylus). Defaults to plain css
-  -v, --version          Output framework version
-  -h, --help             Output help information
-
-
-
- - diff --git a/2x/docs/executable.md b/2x/docs/executable.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/executable.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/guide.html b/2x/docs/guide.html deleted file mode 100644 index 64e9eaea..00000000 --- a/2x/docs/guide.html +++ /dev/null @@ -1,1807 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -

Installation

- -
$ npm install express
-
- -

or to access the express(1) executable install globally:

- -
$ npm install -g express
-
- -

Quick Start

- -

The quickest way to get started with express is to utilize the executable express(1) to generate an application as shown below:

- -

Create the app:

- -
$ npm install -g express
-$ express /tmp/foo && cd /tmp/foo
-
- -

Install dependencies:

- -
$ npm install -d
-
- -

Start the server:

- -
$ node app.js
-
- -

Creating A Server

- -

To create an instance of the express.HTTPServer, simply invoke the createServer() method. With our instance app we can then define routes based on the HTTP verbs, in this example app.get().

- -
var app = require('express').createServer();
-
-app.get('/', function(req, res){
-  res.send('hello world');
-});
-
-app.listen(3000);
-
- -

Creating An HTTPS Server

- -

To initialize a express.HTTPSServer we do the same as above, however we - pass an options object, accepting key, cert and the others mentioned in node’s https documentation.

- -
 var app = require('express').createServer({ key: ... });
-
- -

Configuration

- -

Express supports arbitrary environments, such as production and development. Developers -can use the configure() method to setup needs required by the current environment. When -configure() is called without an environment name it will be run in every environment -prior to the environment specific callback.

- -

In the example below we only dumpExceptions, and respond with exception stack traces -in development mode, however for both environments we utilize methodOverride and bodyParser. -Note the use of app.router, which can (optionally) be used to mount the application routes, -otherwise the first call to app.get(), app.post(), etc will mount the routes.

- -
app.configure(function(){
-    app.use(express.methodOverride());
-    app.use(express.bodyParser());
-    app.use(app.router);
-});
-
-app.configure('development', function(){
-    app.use(express.static(__dirname + '/public'));
-    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
-});
-
-app.configure('production', function(){
-  var oneYear = 31557600000;
-  app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
-  app.use(express.errorHandler());
-});
-
- -

For internal and arbitrary settings Express provides the set(key[, val]), enable(key), disable(key) methods:

- -
 app.configure(function(){
-    app.set('views', __dirname + '/views');
-    app.set('views');
-    // => "/absolute/path/to/views"
-
-    app.enable('some feature');
-    // same as app.set('some feature', true);
-
-    app.disable('some feature');
-    // same as app.set('some feature', false);
-
-    app.enabled('some feature')
-    // => false
- });
-
- -

To alter the environment we can set the NODE_ENV environment variable, for example:

- -
$ NODE_ENV=production node app.js
-
- -

This is very important, as many caching mechanisms are only enabled when in production.

- -

Settings

- -

Express supports the following settings out of the box:

- - - - -

Routing

- -

Express utilizes the HTTP verbs to provide a meaningful, expressive routing API. -For example we may want to render a user’s account for the path /user/12, this -can be done by defining the route below. The values associated to the named placeholders -are available as req.params.

- -
app.get('/user/:id', function(req, res){
-    res.send('user ' + req.params.id);
-});
-
- -

A route is simple a string which is compiled to a RegExp internally. For example -when /user/:id is compiled, a simplified version of the regexp may look similar to:

- -
\/user\/([^\/]+)\/?
-
- -

Regular expression literals may also be passed for complex uses. Since capture -groups with literal RegExp’s are anonymous we can access them directly req.params. So our first capture group would be req.params[0] and the second would follow as req.params[1].

- -
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
-    res.send(req.params);
-});
-
- -

Curl requests against the previously defined route:

- -
   $ curl http://dev:3000/user
-   [null,null]
-   $ curl http://dev:3000/users
-   [null,null]
-   $ curl http://dev:3000/users/1
-   ["1",null]
-   $ curl http://dev:3000/users/1..15
-   ["1","15"]
-
- -

Below are some route examples, and the associated paths that they -may consume:

- -
 "/user/:id"
- /user/12
-
- "/users/:id?"
- /users/5
- /users
-
- "/files/*"
- /files/jquery.js
- /files/javascripts/jquery.js
-
- "/file/*.*"
- /files/jquery.js
- /files/javascripts/jquery.js
-
- "/user/:id/:operation?"
- /user/1
- /user/1/edit
-
- "/products.:format"
- /products.json
- /products.xml
-
- "/products.:format?"
- /products.json
- /products.xml
- /products
-
- "/user/:id.:format?"
- /user/12
- /user/12.json
-
- -

For example we can POST some json, and echo the json back using the bodyParser middleware which will parse json request bodies (as well as others), and place the result in req.body:

- -
var express = require('express')
-  , app = express.createServer();
-
-app.use(express.bodyParser());
-
-app.post('/', function(req, res){
-  res.send(req.body);
-});
-
-app.listen(3000);
-
- -

Typically we may use a “dumb” placeholder such as “/user/:id” which has no restrictions, however say for example we are limiting a user id to digits, we may use ‘/user/:id([0-9]+)’ which will not match unless the placeholder value contains only digits.

- -

Passing Route Control

- -

We may pass control to the next matching route, by calling the third argument, -the next() function. When a match cannot be made, control is passed back to Connect, -and middleware continue to be invoked in the order that they are added via use(). The same is true for several routes which have the same path defined, they will simply be executed in order until one does not call next() and decides to respond.

- -
app.get('/users/:id?', function(req, res, next){
-    var id = req.params.id;
-    if (id) {
-        // do something
-    } else {
-        next();
-    }
-});
-
-app.get('/users', function(req, res){
-    // do something else
-});
-
- -

The app.all() method is useful for applying the same logic for all HTTP verbs in a single call. Below we use this to load a user from our fake database, and assign it to req.user.

- -
var express = require('express')
-  , app = express.createServer();
-
-var users = [{ name: 'tj' }];
-
-app.all('/user/:id/:op?', function(req, res, next){
-  req.user = users[req.params.id];
-  if (req.user) {
-    next();
-  } else {
-    next(new Error('cannot find user ' + req.params.id));
-  }
-});
-
-app.get('/user/:id', function(req, res){
-  res.send('viewing ' + req.user.name);
-});
-
-app.get('/user/:id/edit', function(req, res){
-  res.send('editing ' + req.user.name);
-});
-
-app.put('/user/:id', function(req, res){
-  res.send('updating ' + req.user.name);
-});
-
-app.get('*', function(req, res){
-  res.send('what???', 404);
-});
-
-app.listen(3000); 
-
- -

Middleware

- -

Middleware via Connect can be -passed to express.createServer() as you would with a regular Connect server. For example:

- -
  var express = require('express');
-
-var app = express.createServer(
-      express.logger()
-    , express.bodyParser()
-  );
-
- -

Alternatively we can use() them which is useful when adding middleware within configure() blocks, in a progressive manner.

- -
app.use(express.logger({ format: ':method :url' }));
-
- -

Typically with connect middleware you would require(‘connect’) like so:

- -
var connect = require('connect');
-app.use(connect.logger());
-app.use(connect.bodyParser());
-
- -

This is somewhat annoying, so express re-exports these middleware properties, however they are identical:

- -
app.use(express.logger());
-app.use(express.bodyParser());
-
- -

Middleware ordering is important, when Connect receives a request the first middleware we pass to createServer() or use() is executed with three parameters, request, response, and a callback function usually named next. When next() is invoked the second middleware will then have it’s turn and so on. This is important to note because many middleware depend on each other, for example methodOverride() checks req.body.method for the HTTP method override, however bodyParser() parses the request body and populates req.body. Another example of this is cookie parsing and session support, we must first use() cookieParser() followed by session()_.

- -

Many Express applications may contain the line app.use(app.router), while this may appear strange, it’s simply the middleware function that contains all defined routes, and performs route lookup based on the current request url and HTTP method. Express allows you to position this middleware, though by default it will be added to the bottom. By positioning the router, we can alter middleware precedence, for example we may want to add error reporting as the last middleware so that any exception passed to next() will be handled by it, or perhaps we want static file serving to have low precedence, allowing our routes to intercept requests to a static file to count downloads etc. This may look a little like below

- -
app.use(express.logger(...));
-app.use(express.bodyParser(...));
-app.use(express.cookieParser(...));
-app.use(express.session(...));
-app.use(app.router);
-app.use(express.static(...));
-app.use(express.errorHandler(...));
-
- -

First we add logger() so that it may wrap node’s req.end() method, providing us with response-time data. Next the request’s body will be parsed (if any), followed by cookie parsing and session support, meaning req.session will be defined by the time we hit our routes in app.router. If a request such as GET /javascripts/jquery.js is handled by our routes, and we do not call next() then the static() middleware will never see this request, however if were to define a route as shown below, we can record stats, refuse downloads, consume download credits etc.

- -
var downloads = {};
-
-app.use(app.router);
-app.use(express.static(__dirname + '/public'));
-
-app.get('/*', function(req, res, next){
-  var file = req.params[0];
-  downloads[file] = downloads[file] || 0;
-  downloads[file]++;
-  next();
-});
-
- -

Route Middleware

- -

Routes may utilize route-specific middleware by passing one or more additional callbacks (or arrays) to the method. This feature is extremely useful for restricting access, loading data used by the route etc.

- -

Typically async data retrieval might look similar to below, where we take the :id parameter, and attempt loading a user.

- -
app.get('/user/:id', function(req, res, next){
-  loadUser(req.params.id, function(err, user){
-    if (err) return next(err);
-    res.send('Viewing user ' + user.name);
-  });
-});
-
- -

To keep things DRY and to increase readability we can apply this logic within a middleware. As you can see below, abstracting this logic into middleware allows us to reuse it, and clean up our route at the same time.

- -
function loadUser(req, res, next) {
-  // You would fetch your user from the db
-  var user = users[req.params.id];
-  if (user) {
-    req.user = user;
-    next();
-  } else {
-    next(new Error('Failed to load user ' + req.params.id));
-  }
-}
-
-app.get('/user/:id', loadUser, function(req, res){
-  res.send('Viewing user ' + req.user.name);
-});
-
- -

Multiple route middleware can be applied, and will be executed sequentially to apply further logic such as restricting access to a user account. In the example below only the authenticated user may edit his/her account.

- -
function andRestrictToSelf(req, res, next) {
-  req.authenticatedUser.id == req.user.id
-    ? next()
-    : next(new Error('Unauthorized'));
-}
-
-app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
-  res.send('Editing user ' + req.user.name);
-});
-
- -

Keeping in mind that middleware are simply functions, we can define function that returns the middleware in order to create a more expressive and flexible solution as shown below.

- -
function andRestrictTo(role) {
-  return function(req, res, next) {
-    req.authenticatedUser.role == role
-      ? next()
-      : next(new Error('Unauthorized'));
-  }
-}
-
-app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
-  res.send('Deleted user ' + req.user.name);
-});
-
- -

Commonly used “stacks” of middleware can be passed as an array (applied recursively), which can be mixed and matched to any degree.

- -
var a = [middleware1, middleware2]
-  , b = [middleware3, middleware4]
-  , all = [a, b];
-
-app.get('/foo', a, function(){});
-app.get('/bar', a, function(){});
-
-app.get('/', a, middleware3, middleware4, function(){});
-app.get('/', a, b, function(){});
-app.get('/', all, function(){});
-
- -

For this example in full, view the route middleware example in the repository.

- -

There are times when we may want to “skip” passed remaining route middleware, but continue matching subsequent routes. To do this we invoke next() with the string “route” next('route'). If no remaining routes match the request url then Express will respond with 404 Not Found.

- -

HTTP Methods

- -

We have seen app.get() a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as app.post(), app.del(), etc.

- -

A common example for POST usage, is when “submitting” a form. Below we simply set our form method to “post” in our html, and control will be given to the route we have defined below it.

- -
 <form method="post" action="/">
-     <input type="text" name="user[name]" />
-     <input type="text" name="user[email]" />
-     <input type="submit" value="Submit" />
- </form>
-
- -

By default Express does not know what to do with this request body, so we should add the bodyParser middleware, which will parse application/x-www-form-urlencoded and application/json request bodies and place the variables in req.body. We can do this by “using” the middleware as shown below:

- -
app.use(express.bodyParser());
-
- -

Our route below will now have access to the req.body.user object which will contain the name and email properties when defined.

- -
app.post('/', function(req, res){
-  console.log(req.body.user);
-  res.redirect('back');
-});
-
- -

When using methods such as PUT with a form, we can utilize a hidden input named _method, which can be used to alter the HTTP method. To do so we first need the methodOverride middleware, which should be placed below bodyParser so that it can utilize it’s req.body containing the form values.

- -
app.use(express.bodyParser());
-app.use(express.methodOverride());
-
- -

The reason that these are not always defaults, is simply because these are not required for Express to be fully functional. Depending on the needs of your application, you may not need these at all, your methods such as PUT and DELETE can still be accessed by clients which can use them directly, although methodOverride provides a great solution for forms. Below shows what the usage of PUT might look like:

- -
<form method="post" action="/">
-  <input type="hidden" name="_method" value="put" />
-  <input type="text" name="user[name]" />
-  <input type="text" name="user[email]" />
-  <input type="submit" value="Submit" />    
-</form>
-
-app.put('/', function(){
-    console.log(req.body.user);
-    res.redirect('back');
-});
-
- -

Error Handling

- -

Express provides the app.error() method which receives exceptions thrown within a route, -or passed to next(err). Below is an example which serves different pages based on our -ad-hoc NotFound exception:

- -
function NotFound(msg){
-  this.name = 'NotFound';
-  Error.call(this, msg);
-  Error.captureStackTrace(this, arguments.callee);
-}
-
-NotFound.prototype.__proto__ = Error.prototype;
-
-app.get('/404', function(req, res){
-  throw new NotFound;
-});
-
-app.get('/500', function(req, res){
-  throw new Error('keyboard cat!');
-});
-
- -

We can call app.error() several times as shown below. -Here we check for an instanceof NotFound and show the -404 page, or we pass on to the next error handler.

- -

Note that these handlers can be defined anywhere, as they -will be placed below the route handlers on listen(). This -allows for definition within configure() blocks so we can -handle exceptions in different ways based on the environment.

- -
app.error(function(err, req, res, next){
-    if (err instanceof NotFound) {
-        res.render('404.jade');
-    } else {
-        next(err);
-    }
-});
-
- -

Here we assume all errors as 500 for the simplicity of -this demo, however you can choose whatever you like. For example when node performs filesystem syscalls, you may receive an error object with the error.code of ENOENT, meaning “no such file or directory”, we can utilize this in our error handling and display a page specific to this if desired.

- -
app.error(function(err, req, res){
-  res.render('500.jade', {
-     error: err
-  });
-});
-
- -

Our apps could also utilize the Connect errorHandler middleware -to report on exceptions. For example if we wish to output exceptions -in “development” mode to stderr we can use:

- -
app.use(express.errorHandler({ dumpExceptions: true }));
-
- -

Also during development we may want fancy html pages to show exceptions -that are passed or thrown, so we can set showStack to true:

- -
app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));
-
- -

The errorHandler middleware also responds with json if Accept: application/json -is present, which is useful for developing apps that rely heavily on client-side JavaScript.

- -

Route Param Pre-conditions

- -

Route param pre-conditions can drastically improve the readability of your application, through implicit loading of data, and validation of request urls. For example if you are constantly fetching common data for several routes, such as loading a user for /user/:id, we might typically do something like below:

- -
app.get('/user/:userId', function(req, res, next){
-  User.get(req.params.userId, function(err, user){
-    if (err) return next(err);
-    res.send('user ' + user.name);
-  });
-}); 
-
- -

With preconditions our params can be mapped to callbacks which may perform validation, coercion, or even loading data from a database. Below we invoke app.param() with the parameter name we wish to map to some middleware, as you can see we receive the id argument which contains the placeholder value. Using this we load the user and perform error handling as usual, and simple call next() to pass control to the next precondition or route handler.

- -
app.param('userId', function(req, res, next, id){
-  User.get(id, function(err, user){
-    if (err) return next(err);
-    if (!user) return next(new Error('failed to find user'));
-    req.user = user;
-    next();
-  });
-});
-
- -

Doing so, as mentioned drastically improves our route readability, and allows us to easily share this logic throughout our application:

- -
app.get('/user/:userId', function(req, res){
-  res.send('user ' + req.user.name);
-});
-
- -

View Rendering

- -

View filenames take the form “<name>.<engine>”, where <engine> is the name -of the module that will be required. For example the view layout.ejs will -tell the view system to require(‘ejs’), the module being loaded must export the method exports.compile(str, options), and return a Function to comply with Express. To alter this behaviour -app.register() can be used to map engines to file extensions, so that for example “foo.html” can be rendered by ejs.

- -

Below is an example using Jade to render index.html, -and since we do not use layout: false the rendered contents of index.jade will be passed as -the body local variable in layout.jade.

- -
app.get('/', function(req, res){
-    res.render('index.jade', { title: 'My Site' });
-});
-
- -

The new view engine setting allows us to specify our default template engine, -so for example when using jade we could set:

- -
app.set('view engine', 'jade');
-
- -

Allowing us to render with:

- -
res.render('index');
-
- -

vs:

- -
res.render('index.jade');
-
- -

When view engine is set, extensions are entirely optional, however we can still -mix and match template engines:

- -
res.render('another-page.ejs');
-
- -

Express also provides the view options setting, which is applied each time a view is rendered, so for example if you rarely use layouts you may set:

- -
app.set('view options', {
-  layout: false
-});
-
- -

Which can then be overridden within the res.render() call if need be:

- -
res.render('myview.ejs', { layout: true });
-
- -

When an alternate layout is required, we may also specify a path. For example if we have view engine set to jade and a file named ./views/mylayout.jade we can simply pass:

- -
res.render('page', { layout: 'mylayout' });
-
- -

Otherwise we must specify the extension:

- -
res.render('page', { layout: 'mylayout.jade' });
-
- -

These paths may also be absolute:

- -
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
-
- -

A good example of this is specifying custom ejs opening and closing tags:

- -
app.set('view options', {
-    open: '{{',
-    close: '}}'
-});
-
- -

View Partials

- -

The Express view system has built-in support for partials and collections, which are “mini” views representing a document fragment. For example rather than iterating -in a view to display comments, we could use partial collection:

- -
partial('comment', { collection: comments });
-
- -

If no other options or local variables are desired, we can omit the object and simply pass our array, which is equivalent to above:

- -
partial('comment', comments);
-
- -

When using the partial collection support a few “magic” locals are provided -for free:

- - - - -

Local variables passed (or generated) take precedence, however locals passed to the parent view are available in the child view as well. So for example if we were to render a blog post with partial(‘blog/post’, post) it would generate the post local, but the view calling this function had the local user, it would be available to the blog/post view as well.

- -

For documentation on altering the object name view res.partial().

- -

NOTE: be careful about when you use partial collections, as rendering an array with a length of 100 means we have to render 100 views. For simple collections you may inline the iteration instead of using partial collection support to decrease overhead.

- -

View Lookup

- -

View lookup is performed relative to the parent view, for example if we had a page view named views/user/list.jade, and within that view we did partial(‘edit’) it would attempt to load views/user/edit.jade, whereas partial(‘../messages’) would load views/messages.jade.

- -

The view system also allows for index templates, allowing you to have a directory of the same name. For example within a route we may have res.render(‘users’) either views/users.jade, or views/users/index.jade.

- -

When utilizing index views as shown above, we may reference views/users/index.jade from a view in the same directory by partial(‘users’), and the view system will try ../users/index, preventing us from needing to call partial(‘index’).

- -

Template Engines

- -

Below are a few template engines commonly used with Express:

- - - - -

Session Support

- -

Sessions support can be added by using Connect’s session middleware. To do so we also need the cookieParser middleware place above it, which will parse and populate cookie data to req.cookies.

- -
app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat" }));
-
- -

By default the session middleware uses the memory store bundled with Connect, however many implementations exist. For example connect-redis supplies a Redis session store and can be used as shown below:

- -
var RedisStore = require('connect-redis')(express);
-app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
-
- -

Now the req.session and req.sessionStore properties will be accessible to all routes and subsequent middleware. Properties on req.session are automatically saved on a response, so for example if we wish to shopping cart data:

- -
var RedisStore = require('connect-redis')(express);
-app.use(express.bodyParser());
-app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
-
-app.post('/add-to-cart', function(req, res){
-  // Perhaps we posted several items with a form
-  // (use the bodyParser() middleware for this)
-  var items = req.body.items;
-  req.session.items = items;
-  res.redirect('back');
-});
-
-app.get('/add-to-cart', function(req, res){
-  // When redirected back to GET /add-to-cart
-  // we could check req.session.items && req.session.items.length
-  // to print out a message
-  if (req.session.items && req.session.items.length) {
-    req.flash('info', 'You have %s items in your cart', req.session.items.length);
-  }
-  res.render('shopping-cart');
-});
-
- -

The req.session object also has methods such as Session#touch(), Session#destroy(), Session#regenerate() among others to maintain and manipulate sessions. For more information view the Connect Session documentation.

- -

Migration Guide

- -

Express 1.x developers may reference the Migration Guide to get up to speed on how to upgrade your application to work with Express 2.x, Connect 1.x, and Node 0.4.x.

- -

req.header(key[, defaultValue])

- -

Get the case-insensitive request header key, with optional defaultValue:

- -
req.header('Host');
-req.header('host');
-req.header('Accept', '*/*');
-
- -

The Referrer and Referer header fields are special-cased, either will work:

- -
// sent Referrer: http://google.com
-
-req.header('Referer');
-// => "http://google.com"
-
-req.header('Referrer');
-// => "http://google.com"
-
- -

req.accepts(type)

- -

Check if the Accept header is present, and includes the given type.

- -

When the Accept header is not present true is returned. Otherwise -the given type is matched by an exact match, and then subtypes. You -may pass the subtype such as “html” which is then converted internally -to “text/html” using the mime lookup table.

- -
// Accept: text/html
-req.accepts('html');
-// => true
-
-// Accept: text/*; application/json
-req.accepts('html');
-req.accepts('text/html');
-req.accepts('text/plain');
-req.accepts('application/json');
-// => true
-
-req.accepts('image/png');
-req.accepts('png');
-// => false
-
- -

req.is(type)

- -

Check if the incoming request contains the Content-Type -header field, and it contains the give mime type.

- -
   // With Content-Type: text/html; charset=utf-8
-   req.is('html');
-   req.is('text/html');
-   // => true
-
-   // When Content-Type is application/json
-   req.is('json');
-   req.is('application/json');
-   // => true
-
-   req.is('html');
-   // => false
-
- -

Ad-hoc callbacks can also be registered with Express, to perform -assertions again the request, for example if we need an expressive -way to check if our incoming request is an image, we can register “an image” -callback:

- -
    app.is('an image', function(req){
-      return 0 == req.headers['content-type'].indexOf('image');
-    });
-
- -

Now within our route callbacks, we can use to to assert content types -such as “image/jpeg”, “image/png”, etc.

- -
   app.post('/image/upload', function(req, res, next){
-     if (req.is('an image')) {
-       // do something
-     } else {
-       next();
-     }
-   });
-
- -

Keep in mind this method is not limited to checking Content-Type, you -can perform any request assertion you wish.

- -

Wildcard matches can also be made, simplifying our example above for “an image”, by asserting the subtype only:

- -
req.is('image/*');
-
- -

We may also assert the type as shown below, which would return true for “application/json”, and “text/json”.

- -
req.is('*/json');
-
- -

req.param(name[, default])

- -

Return the value of param name when present or default.

- - - - -

To utilize urlencoded request bodies, req.body -should be an object. This can be done by using -the _express.bodyParser middleware.

- -

req.get(field, param)

- -

Get field’s param value, defaulting to ‘’ when the param - or field is not present.

- -
 req.get('content-disposition', 'filename');
- // => "something.png"
-
- req.get('Content-Type', 'boundary');
- // => "--foo-bar-baz"
-
- -

req.flash(type[, msg])

- -

Queue flash msg of the given type.

- -
req.flash('info', 'email sent');
-req.flash('error', 'email delivery failed');
-req.flash('info', 'email re-sent');
-// => 2
-
-req.flash('info');
-// => ['email sent', 'email re-sent']
-
-req.flash('info');
-// => []
-
-req.flash();
-// => { error: ['email delivery failed'], info: [] }
-
- -

Flash notification message may also utilize formatters, by default only the %s string formatter is available:

- -
req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);
-
- -

req.isXMLHttpRequest

- -

Also aliased as req.xhr, this getter checks the X-Requested-With header -to see if it was issued by an XMLHttpRequest:

- -
req.xhr
-req.isXMLHttpRequest
-
- -

res.header(key[, val])

- -

Get or set the response header key.

- -
res.header('Content-Length');
-// => undefined
-
-res.header('Content-Length', 123);
-// => 123
-
-res.header('Content-Length');
-// => 123
-
- -

res.charset

- -

Sets the charset for subsequent Content-Type header fields. For example res.send() and res.render() default to “utf8”, so we may explicitly set the charset before rendering a template:

- -
res.charset = 'ISO-8859-1';
-res.render('users');
-
- -

or before responding with res.send():

- -
res.charset = 'ISO-8859-1';
-res.send(str);
-
- -

or with node’s res.end():

- -
res.charset = 'ISO-8859-1';
-res.header('Content-Type', 'text/plain');
-res.end(str);
-
- -

res.contentType(type)

- -

Sets the Content-Type response header to the given type.

- -
  var filename = 'path/to/image.png';
-  res.contentType(filename);
-  // Content-Type is now "image/png"
-
- -

A literal Content-Type works as well:

- -
  res.contentType('application/json');
-
- -

Or simply the extension without leading .:

- -
  res.contentType('json');
-
- -

res.attachment([filename])

- -

Sets the Content-Disposition response header to “attachment”, with optional filename.

- -
  res.attachment('path/to/my/image.png');
-
- -

res.sendfile(path[, options[, callback]])

- -

Used by res.download() to transfer an arbitrary file.

- -
res.sendfile('path/to/my.file');
-
- -

This method accepts an optional callback which is called when -an error occurs, or when the transfer is complete. By default failures call next(err), however when a callback is supplied you must do this explicitly, or act on the error.

- -
res.sendfile(path, function(err){
-  if (err) {
-    next(err);
-  } else {
-    console.log('transferred %s', path);
-  }
-});
-
- -

Options may also be passed to the internal fs.createReadStream() call, for example altering the bufferSize:

- -
res.sendfile(path, { bufferSize: 1024 }, function(err){
-  // handle
-});
-
- -

res.download(file[, filename[, callback[, callback2]]])

- -

Transfer the given file as an attachment with optional alternative filename.

- -
res.download('path/to/image.png');
-res.download('path/to/image.png', 'foo.png');
-
- -

This is equivalent to:

- -
res.attachment(file);
-res.sendfile(file);
-
- -

An optional callback may be supplied as either the second or third argument, which is passed to res.sendfile(). Within this callback you may still respond, as the header has not been sent.

- -
res.download(path, 'expenses.doc', function(err){
-  // handle
-});
-
- -

An optional second callback, callback2 may be given to allow you to act on connection related errors, however you should not attempt to respond.

- -
res.download(path, function(err){
-  // error or finished
-}, function(err){
-  // connection related error
-});
-
- -

res.send(body|status[, headers|status[, status]])

- -

The res.send() method is a high level response utility allowing you to pass -objects to respond with json, strings for html, Buffer instances, or numbers representing the status code. The following are all valid uses:

- -
 res.send(); // 204
- res.send(new Buffer('wahoo'));
- res.send({ some: 'json' });
- res.send('<p>some html</p>');
- res.send('Sorry, cant find that', 404);
- res.send('text', { 'Content-Type': 'text/plain' }, 201);
- res.send(404);
-
- -

By default the Content-Type response header is set, however if explicitly -assigned through res.send() or previously with res.header() or res.contentType() -it will not be set again.

- -

Note that this method end()s the response, so you will want to use node’s res.write() for multiple writes or streaming.

- -

res.redirect(url[, status])

- -

Redirect to the given url with a default response status of 302.

- -
res.redirect('/', 301);
-res.redirect('/account');
-res.redirect('http://google.com');
-res.redirect('home');
-res.redirect('back');
-
- -

Express supports “redirect mapping”, which by default provides home, and back. -The back map checks the Referrer and Referer headers, while home utilizes -the “home” setting and defaults to “/”.

- -

res.cookie(name, val[, options])

- -

Sets the given cookie name to val, with options httpOnly, secure, expires etc.

- -
// "Remember me" for 15 minutes 
-res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });
-
- -

The maxAge property may be used to set expires relative to Date.now() in milliseconds, so our example above can now become:

- -
res.cookie('rememberme', 'yes', { maxAge: 900000 });
-
- -

To parse incoming Cookie headers, use the cookieParser middleware, which provides the req.cookies object:

- -
app.use(express.cookieParser());
-
-app.get('/', function(req, res){
-  // use req.cookies.rememberme
-});
-
- -

res.clearCookie(name[, options])

- -

Clear cookie name by setting “expires” far in the past.

- -
res.clearCookie('rememberme');
-
- -

res.render(view[, options[, fn]])

- -

Render view with the given options and optional callback fn. -When a callback function is given a response will not be made -automatically, however otherwise a response of 200 and text/html is given.

- -

The options passed are the local variables as well, for example if we want to expose “user” to the view, and prevent a local we do so within the same object:

- -
var user = { name: 'tj' };
-res.render('index', { layout: false, user: user });
-
- -

res.partial(view[, options])

- -

Render view partial with the given options. This method is always available -to the view as a local variable.

- - - - -

The following are equivalent, and the name of collection value when passed -to the partial will be movie as derived from the name.

- -
partial('theatre/movie.jade', { collection: movies });
-partial('theatre/movie.jade', movies);
-partial('movie.jade', { collection: movies });
-partial('movie.jade', movies);
-partial('movie', movies);
-// In view: movie.director
-
- -

To change the local from movie to video we can use the “as” option:

- -
partial('movie', { collection: movies, as: 'video' });
-// In view: video.director
-
- -

Also we can make our movie the value of this within our view so that instead -of movie.director we could use this.director.

- -
partial('movie', { collection: movies, as: this });
-// In view: this.director
-
- -

Another alternative is to “expand” the properties of the collection item into -pseudo globals (local variables) by using as: global, which again is syntactic sugar:

- -
partial('movie', { collection: movies, as: global });
-// In view: director
-
- -

This same logic applies to a single partial object usage:

- -
partial('movie', { object: movie, as: this });
-// In view: this.director
-
-partial('movie', { object: movie, as: global });
-// In view: director
-
-partial('movie', { object: movie, as: 'video' });
-// In view: video.director
-
-partial('movie', { object: movie });
-// In view: movie.director
-
- -

When a non-collection (does not have .length) is passed as the second argument, it is assumed to be the object, after which the object’s local variable name is derived from the view name:

- -
var movie = new Movie('Nightmare Before Christmas', 'Tim Burton')
-partial('movie', movie)
-// => In view: movie.director
-
- -

The exception of this, is when a “plain” object, aka “{}” or “new Object” is passed, which is considered an object with local variable. For example some may expect a “movie” local with the following, however since it is a plain object “director” and “title” are simply locals:

- -
var movie = { title: 'Nightmare Before Christmas', director: 'Tim Burton' }; 
-partial('movie', movie)
-
- -

For cases like this where passing a plain object is desired, simply assign it to a key, or use the object key which will use the filename-derived variable name. The examples below are equivalent:

- -
 partial('movie', { locals: { movie: movie }})
- partial('movie', { movie: movie })
- partial('movie', { object: movie })
-
- -

This exact API can be utilized from within a route, to respond with a fragment via Ajax or WebSockets, for example we can render a collection of users directly from a route:

- -
app.get('/users', function(req, res){
-  if (req.xhr) {
-    // respond with the each user in the collection
-    // passed to the "user" view
-    res.partial('user', users);
-  } else {
-    // respond with layout, and users page
-    // which internally does partial('user', users)
-    // along with other UI
-    res.render('users', { users: users });
-  }
-});
-
- -

res.local(name[, val])

- -

Get or set the given local variable name. The locals built up for a response are applied to those given to the view rendering methods such as res.render().

- -
  app.all('/movie/:id', function(req, res, next){
-    Movie.get(req.params.id, function(err, movie){
-      // Assigns res.locals.movie = movie
-      res.local('movie', movie);
-    });
-  });
-
-  app.get('/movie/:id', function(req, res){
-    // movie is already a local, however we
-    // can pass more if we wish
-    res.render('movie', { displayReviews: true });
-  });
-
- -

res.locals(obj)

- -

Assign several locals with the given obj. The following are equivalent:

- -
 res.local('foo', bar);
- res.local('bar', baz);
-
- res.locals({ foo: bar, bar, baz });
-
- -

app.set(name[, val])

- -

Apply an application level setting name to val, or -get the value of name when val is not present:

- -
app.set('views', __dirname + '/views');
-app.set('views');
-// => ...path...
-
- -

Alternatively you may simply access the settings via app.settings:

- -
app.settings.views
-// => ...path...
-
- -

app.enable(name)

- -

Enable the given setting name:

- -
app.enable('some arbitrary setting');
-app.set('some arbitrary setting');
-// => true
-
-app.enabled('some arbitrary setting');
-// => true
-
- -

app.enabled(name)

- -

Check if setting name is enabled:

- -
app.enabled('view cache');
-// => false
-
-app.enable('view cache');
-app.enabled('view cache');
-// => true
-
- -

app.disable(name)

- -

Disable the given setting name:

- -
app.disable('some setting');
-app.set('some setting');
-// => false
-
-app.disabled('some setting');
-// => false
-
- -

app.disabled(name)

- -

Check if setting name is disabled:

- -
app.enable('view cache');
-
-app.disabled('view cache');
-// => false
-
-app.disable('view cache');
-app.disabled('view cache');
-// => true
-
- -

app.configure(env|function[, function])

- -

Define a callback function for the given env (or all environments) with callback function:

- -
app.configure(function(){
-    // executed for each env
-});
-
-app.configure('development', function(){
-    // executed for 'development' only
-});
-
- -

app.redirect(name, val)

- -

For use with res.redirect() we can map redirects at the application level as shown below:

- -
app.redirect('google', 'http://google.com');
-
- -

Now in a route we may call:

- -

res.redirect(‘google’);

- -

We may also map dynamic redirects:

- -
app.redirect('comments', function(req, res){
-  return '/post/' + req.params.id + '/comments';
-});
-
- -

So now we may do the following, and the redirect will dynamically adjust to -the context of the request. If we called this route with GET /post/12 our -redirect Location would be /post/12/comments.

- -
app.get('/post/:id', function(req, res){
-  res.redirect('comments');
-});
-
- -

When mounted, res.redirect() will respect the mount-point. For example if a blog app is mounted at /blog, the following will redirect to /blog/posts:

- -
res.redirect('/posts');
-
- -

app.error(function)

- -

Adds an error handler function which will receive the exception as the first parameter as shown below. -Note that we may set several error handlers by making several calls to this method, however the handler -should call next(err) if it does not wish to deal with the exception:

- -
app.error(function(err, req, res, next){
-  res.send(err.message, 500);
-});
-
- -

app.helpers(obj)

- -

Registers static view helpers.

- -
app.helpers({
-    name: function(first, last){ return first + ', ' + last }
-  , firstName: 'tj'
-  , lastName: 'holowaychuk'
-});
-
- -

Our view could now utilize the firstName and lastName variables, -as well as the name() function exposed.

- -
<%= name(firstName, lastName) %>
-
- -

Express also provides a few locals by default:

- -
- `settings`  the app's settings object
-- `filename`  the view's filename
-- `layout(path)`  specify the layout from within a view
-
- -

This method is aliased as app.locals().

- -

app.dynamicHelpers(obj)

- -

Registers dynamic view helpers. Dynamic view helpers -are simply functions which accept req, res, and are -evaluated against the Server instance before a view is rendered. The return value of this function -becomes the local variable it is associated with.

- -
app.dynamicHelpers({
-  session: function(req, res){
-    return req.session;
-  }
-});
-
- -

All views would now have session available so that session data can be accessed via session.name etc:

- -
<%= session.name %>
-
- -

app.lookup

- -

The app.lookup http methods returns an array of callback functions - associated with the given path.

- -

Suppose we define the following routes:

- -
  app.get('/user/:id', function(){});
-  app.put('/user/:id', function(){});
-  app.get('/user/:id/:op?', function(){});
-
- -

We can utilize this lookup functionality to check which routes - have been defined, which can be extremely useful for higher level - frameworks built on Express.

- -
  app.lookup.get('/user/:id');
-  // => [Function]
-
-  app.lookup.get('/user/:id/:op?');
-  // => [Function]
-
-  app.lookup.put('/user/:id');
-  // => [Function]
-
-  app.lookup.all('/user/:id');
-  // => [Function, Function]
-
-  app.lookup.all('/hey');
-  // => []
-
- -

To alias app.lookup.VERB(), we can simply invoke app.VERB() - without a callback, as a shortcut, for example the following are - equivalent:

- -
  app.lookup.get('/user');
-  app.get('/user');
-
- -

Each function returned has the following properties:

- -
  var fn = app.get('/user/:id/:op?')[0];
-
-  fn.regexp
-  // => /^\/user\/(?:([^\/]+?))(?:\/([^\/]+?))?\/?$/i
-
-  fn.keys
-  // => ['id', 'op']
-
-  fn.path
-  // => '/user/:id/:op?'
-
-  fn.method
-  // => 'GET'
-
- -

app.match

- -

The app.match http methods return an array of callback functions - which match the given url, which may include a query string etc. This - is useful when you want reflect on which routes have the opportunity to - respond.

- -

Suppose we define the following routes:

- -
    app.get('/user/:id', function(){});
-    app.put('/user/:id', function(){});
-    app.get('/user/:id/:op?', function(){});
-
- -

Our match against GET will return two functions, since the :op - in our second route is optional.

- -
  app.match.get('/user/1');
-  // => [Function, Function]
-
- -

This second call returns only the callback for /user/:id/:op?.

- -
  app.match.get('/user/23/edit');
-  // => [Function]
-
- -

We can also use all() to disregard the http method:

- -
  app.match.all('/user/20');
-  // => [Function, Function, Function]
-
- -

Each function matched has the following properties:

- -
  var fn = app.match.get('/user/23/edit')[0];
-
-  fn.keys
-  // => ['id', 'op']
-
-  fn.params
-  // => { id: '23', op: 'edit' }
-
-  fn.method
-  // => 'GET'
-
- -

app.mounted(fn)

- -

Assign a callback fn which is called when this Server is passed to Server#use().

- -
var app = express.createServer(),
-    blog = express.createServer();
-
-blog.mounted(function(parent){
-  // parent is app
-  // "this" is blog
-});
-
-app.use(blog);
-
- -

app.register(ext, exports)

- -

Register the given template engine exports -as ext. For example we may wish to map “.html” -files to jade:

- -
 app.register('.html', require('jade'));
-
- -

This is also useful for libraries that may not -match extensions correctly. For example my haml.js -library is installed from npm as “hamljs” so instead -of layout.hamljs, we can register the engine as “.haml”:

- -
 app.register('.haml', require('haml-js'));
-
- -

For engines that do not comply with the Express -specification, we can also wrap their api this way. Below -we map .md to render markdown files, rendering the html once -since it will not change on subsequent calls, and support local substitution -in the form of “{name}”.

- -
  app.register('.md', {
-    compile: function(str, options){
-      var html = md.toHTML(str);
-      return function(locals){
-        return html.replace(/\{([^}]+)\}/g, function(_, name){
-          return locals[name];
-        });
-      };
-    }
-  });
-
- -

app.listen([port[, host]])

- -

Bind the app server to the given port, which defaults to 3000. When host is omitted all -connections will be accepted via INADDR_ANY.

- -
app.listen();
-app.listen(3000);
-app.listen(3000, 'n.n.n.n');
-
- -

The port argument may also be a string representing the path to a unix domain socket:

- -
app.listen('/tmp/express.sock');
-
- -

Then try it out:

- -
$ telnet /tmp/express.sock
-GET / HTTP/1.1
-
-HTTP/1.1 200 OK
-Content-Type: text/plain
-Content-Length: 11
-
-Hello World
-
-
-
- - diff --git a/2x/docs/guide.md b/2x/docs/guide.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/guide.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/images/apps/clickdummy.png b/2x/docs/images/apps/clickdummy.png deleted file mode 100644 index 5b973e7d..00000000 Binary files a/2x/docs/images/apps/clickdummy.png and /dev/null differ diff --git a/2x/docs/images/apps/developmentseed.png b/2x/docs/images/apps/developmentseed.png deleted file mode 100644 index 7b308d01..00000000 Binary files a/2x/docs/images/apps/developmentseed.png and /dev/null differ diff --git a/2x/docs/images/apps/e-resistable.png b/2x/docs/images/apps/e-resistable.png deleted file mode 100644 index 93df49c1..00000000 Binary files a/2x/docs/images/apps/e-resistable.png and /dev/null differ diff --git a/2x/docs/images/apps/learnboost.png b/2x/docs/images/apps/learnboost.png deleted file mode 100644 index 07cdec96..00000000 Binary files a/2x/docs/images/apps/learnboost.png and /dev/null differ diff --git a/2x/docs/images/apps/markupio.png b/2x/docs/images/apps/markupio.png deleted file mode 100644 index 97784d77..00000000 Binary files a/2x/docs/images/apps/markupio.png and /dev/null differ diff --git a/2x/docs/images/apps/nodeko.png b/2x/docs/images/apps/nodeko.png deleted file mode 100644 index 93c6d0ce..00000000 Binary files a/2x/docs/images/apps/nodeko.png and /dev/null differ diff --git a/2x/docs/images/apps/opowerjobs.png b/2x/docs/images/apps/opowerjobs.png deleted file mode 100644 index b01d21d4..00000000 Binary files a/2x/docs/images/apps/opowerjobs.png and /dev/null differ diff --git a/2x/docs/images/apps/scrabbly.png b/2x/docs/images/apps/scrabbly.png deleted file mode 100644 index f8b2f890..00000000 Binary files a/2x/docs/images/apps/scrabbly.png and /dev/null differ diff --git a/2x/docs/images/apps/storify.png b/2x/docs/images/apps/storify.png deleted file mode 100644 index e3adb547..00000000 Binary files a/2x/docs/images/apps/storify.png and /dev/null differ diff --git a/2x/docs/images/apps/toptwittertrends.png b/2x/docs/images/apps/toptwittertrends.png deleted file mode 100644 index 37f269b5..00000000 Binary files a/2x/docs/images/apps/toptwittertrends.png and /dev/null differ diff --git a/2x/docs/images/apps/widescript.png b/2x/docs/images/apps/widescript.png deleted file mode 100644 index 72102b89..00000000 Binary files a/2x/docs/images/apps/widescript.png and /dev/null differ diff --git a/2x/docs/images/bg.jpg b/2x/docs/images/bg.jpg deleted file mode 100644 index d2e3b085..00000000 Binary files a/2x/docs/images/bg.jpg and /dev/null differ diff --git a/2x/docs/images/bg.tile.jpg b/2x/docs/images/bg.tile.jpg deleted file mode 100644 index 5efe6a3d..00000000 Binary files a/2x/docs/images/bg.tile.jpg and /dev/null differ diff --git a/2x/docs/images/logo.png b/2x/docs/images/logo.png deleted file mode 100644 index 53a747e9..00000000 Binary files a/2x/docs/images/logo.png and /dev/null differ diff --git a/2x/docs/images/top.png b/2x/docs/images/top.png deleted file mode 100644 index 38fbe504..00000000 Binary files a/2x/docs/images/top.png and /dev/null differ diff --git a/2x/docs/index.html b/2x/docs/index.html deleted file mode 100644 index 0f3df5ce..00000000 --- a/2x/docs/index.html +++ /dev/null @@ -1,266 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -
var app = express.createServer();
-
-app.get('/', function(req, res){
-    res.send('Hello World');
-});
-
-app.listen(3000);
-
- -

Features

- - - - -

Contributors

- -

The following are the major contributors of Express (in no specific order).

- - - - -

Third-Party Modules

- -

The following modules compliment or extend Express directly:

- - - - -

More Information

- - - -
-
- - diff --git a/2x/docs/index.md b/2x/docs/index.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/index.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/layout/foot.html b/2x/docs/layout/foot.html deleted file mode 100644 index 066f1158..00000000 --- a/2x/docs/layout/foot.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/2x/docs/layout/head.html b/2x/docs/layout/head.html deleted file mode 100644 index 562582b8..00000000 --- a/2x/docs/layout/head.html +++ /dev/null @@ -1,193 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- diff --git a/2x/docs/migrate.html b/2x/docs/migrate.html deleted file mode 100644 index 7258f70f..00000000 --- a/2x/docs/migrate.html +++ /dev/null @@ -1,394 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -

Express 1.x to 2.x Migration

- -

HTTPS

- -

Creating an HTTPS server is simply, simply pass the TLS options to express.createServer():

- -
 var app = express.createServer({
-     key: ...
-   , cert: ...
- });
-
- app.listen(443);
-
- -

req.header() Referrer

- -

Previously if anyone was doing something similar to:

- -
 req.headers.referrer || req.headers.referer
- req.header('Referrer') || req.header('Referer')
-
- -

With the new special-case we may now simply use Referrer which will return either if defined:

- -
 req.header('Referrer')
-
- -

res.local(name, val)

- -

Previously all local variables had to be passed to res.render(), or either app.helpers() or app.dynamicHelpers(), now we may do this at the request-level progressively. The res.local() method accepts a name and val, however the locals passed to res.render() will take precedence.

- -

For example we may utilize this feature to create locals in middleware:

- -
 function loadUser(req, res, next) {
-   User.get(req.params.id, function(err, user){
-     res.local('user', user);
-     next();
-   });
- }
-
- app.get('/user/:id', loadUser, function(req, res){
-   res.render('user');
- });
-
- -

req.param(name[, defaultValue])

- -

Previously only name was accepted, so some of you may have been doing the following:

- -
 var id = req.param('id') || req.user.id;
-
- -

The new defaultValue argument can handle this nicely:

- -
 var id = req.param('id', req.user.id);
-
- -

app.helpers() / app.locals()

- -

app.locals() is now an alias of app.helpers(), as helpers makes more sense for functions.

- -

req.accepts(type)

- -

req.accepts() now accepts extensions:

- -
  // Accept: text/html
-  req.accepts('html');
-  req.accepts('.html');
-  // => true
-
-  // Accept: text/*; application/json
-  req.accepts('html');
-  req.accepts('text/*');
-  req.accepts('text/plain');
-  req.accepts('application/json');
-  // => true
-
-  req.accepts('image/png');
-  req.accepts('png');
-  // => false
-
- -

res.cookie()

- -

Previously only directly values could be passed, so for example:

- -
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000) });
-
- -

However now we have the alternative maxAge property which may be used to set expires relative to Date.now() in milliseconds, so our example above can now become:

- -
res.cookie('rememberme', 'yes', { maxAge: 900000 });
-
- -

res.download() / res.sendfile()

- -

Both of these methods now utilize Connect’s static file server behind the scenes (actually the previous Express code was ported to Connect 1.0). With this change comes a change to the callback as well. Previously the path and stream were passed, however now only an error is passed, when no error has occurred the callback will be invoked indicating that the file transfer is complete. The callback remains optional:

- -
 res.download('/path/to/file');
-
- res.download('/path/to/file', function(err){
-   if (err) {
-     console.error(err);
-   } else {
-     console.log('transferred');
-   }
- });
-
- -

The stream threshold setting was removed.

- -

res.render()

- -

Previously locals were passed as a separate key:

- -
 res.render('user', { layout: false, locals: { user: user }});
-
- -

In Express 2.0 both the locals and the options are one in the same, meaning you cannot have a local variable named layout as it is reserved for express, however this cleans up the API:

- -
 res.render('user', { layout: false, user: user });
-
- -

res.partial()

- -

Express 2.0 adds the res.partial() method, helpful for rendering partial fragments over WebSockets or Ajax requests etc. The API is identical to the partial() calls within views.

- -
 // render a collection of comments
- res.partial('comment', [comment1, comment2]); 
-
- // render a single comment
- res.partial('comment', comment);
-
- -

partial() locals

- -

Both res.partial() and the partial() functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass user to a partial, along with date like so:

- -
   partial('user', { object: user, locals: { date: new Date }})
-
- -

or perhaps if you preferred not to use the inferred name user you may used a local for this as well:

- -
   partial('user', { locals: { user: user, date: new Date }})
-
- -

With recent changes to Express 2.x the object passed is now both, so the following is valid for the object option and locals:

- -
   partial('user', { object: user, date: new Date })
-
- -

Or the following which is equivalent, however the local var name is explicitly set to user instead of deduced from the filename.

- -
   partial('user', { user: user, date: new Date })
-
- -

When a “basic” object aka {} or new Object is passed, it is considered options, otherwise it is considered the object. The following are equivalent:

- -
  partial('user', user); 
-  partial('user', { object: user }); 
-
- -

Template Engine Compliance

- -

To comply with Express previously engines needed the following signature:

- -
 engine.render(str, options, function(err){});
-
- -

Now they must export a compile() function, returning a function which when called with local variables will render the template. This allows Express to cache the compiled function in memory during production.

- -
 var fn = engine.compile(str, options);
- fn(locals);
-
- -

View Partial Lookup

- -

Previously partials were loaded relative to the now removed view partials directory setting, or by default views/partials, now they are relative to the view calling them, read more on view lookup.

- -

Mime Types

- -

Express and Connect now utilize the mime module in npm, so to add more use:

- -
 require('mime').define({ 'foo/bar': ['foo', 'bar'] });
-
- -

static() middleware

- -

Previously named staticProvider(), the now static() middleware takes a single directory path, followed by options.

- -
 app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
-
- -

Previously when using options the root option would be used for this:

- -
 app.use(express.staticProvider({ root: __dirname + '/public', maxAge: oneYear }));
-
-
-
- - diff --git a/2x/docs/migrate.md b/2x/docs/migrate.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/migrate.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/docs/screencasts.html b/2x/docs/screencasts.html deleted file mode 100644 index 77a0105f..00000000 --- a/2x/docs/screencasts.html +++ /dev/null @@ -1,224 +0,0 @@ - - - Express - node web framework - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- -

Introduction

- -

This introduction screencast covers the basics of Express, and how to get started with your first application.

- - - - -

View Partials

- -

In this screencast we work with partials to display a collection of users using the Jade template engine, and learn about view path resolution.

- - - - -

Route Specific Middleware

- -

In the screencast below we learn about the benefits of route-specific middleware.

- - - - -

Route Param Preconditions

- -

Learn about route parameter (/user/:id) pre-conditions, providing automated validation, and loading of data via the named route param segments.

- - - -
-
- - diff --git a/2x/docs/screencasts.md b/2x/docs/screencasts.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/docs/screencasts.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/executable.html b/2x/executable.html deleted file mode 100644 index 1b35189b..00000000 --- a/2x/executable.html +++ /dev/null @@ -1,240 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -

Synopsis

- -
express [options] [PATH]
-
- -

Description

- -

The express executable generates apps at the given PATH or the -current working directory. Although Express is not bound to a specific -application structure, this executable creates a maintainable base app.

- -

Options

- -
  -s, --sessions         Add session support
-  -t, --template ENGINE  Add template ENGINE support (jade|ejs). Defaults to jade
-  -c, --css ENGINE       Add stylesheet ENGINE support (less|sass|stylus). Defaults to plain css
-  -v, --version          Output framework version
-  -h, --help             Output help information
-
-
-
- - diff --git a/2x/executable.md b/2x/executable.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/executable.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/guide.html b/2x/guide.html deleted file mode 100644 index 1fda4564..00000000 --- a/2x/guide.html +++ /dev/null @@ -1,1863 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -

Installation

- -
$ npm install express
-
- -

or to access the express(1) executable install globally:

- -
$ npm install -g express
-
- -

Quick Start

- -

The quickest way to get started with express is to utilize the executable express(1) to generate an application as shown below:

- -

Create the app:

- -
$ npm install -g express
-$ express /tmp/foo && cd /tmp/foo
-
- -

Install dependencies:

- -
$ npm install -d
-
- -

Start the server:

- -
$ node app.js
-
- -

Creating A Server

- -

To create an instance of the express.HTTPServer, simply invoke the createServer() method. With our instance app we can then define routes based on the HTTP verbs, in this example app.get().

- -
var app = require('express').createServer();
-
-app.get('/', function(req, res){
-  res.send('hello world');
-});
-
-app.listen(3000);
-
- -

Creating An HTTPS Server

- -

To initialize a express.HTTPSServer we do the same as above, however we - pass an options object, accepting key, cert and the others mentioned in node’s https documentation.

- -
 var app = require('express').createServer({ key: ... });
-
- -

Configuration

- -

Express supports arbitrary environments, such as production and development. Developers -can use the configure() method to setup needs required by the current environment. When -configure() is called without an environment name it will be run in every environment -prior to the environment specific callback.

- -

In the example below we only dumpExceptions, and respond with exception stack traces -in development mode, however for both environments we utilize methodOverride and bodyParser. -Note the use of app.router, which can (optionally) be used to mount the application routes, -otherwise the first call to app.get(), app.post(), etc will mount the routes.

- -
app.configure(function(){
-    app.use(express.methodOverride());
-    app.use(express.bodyParser());
-    app.use(app.router);
-});
-
-app.configure('development', function(){
-    app.use(express.static(__dirname + '/public'));
-    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
-});
-
-app.configure('production', function(){
-  var oneYear = 31557600000;
-  app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
-  app.use(express.errorHandler());
-});
-
- -

For similar environments you may also pass several env strings:

- -
app.configure('stage', 'prod', function(){
-  // config
-});
-
- -

For internal and arbitrary settings Express provides the set(key[, val]), enable(key), disable(key) methods:

- -
 app.configure(function(){
-    app.set('views', __dirname + '/views');
-    app.set('views');
-    // => "/absolute/path/to/views"
-
-    app.enable('some feature');
-    // same as app.set('some feature', true);
-
-    app.disable('some feature');
-    // same as app.set('some feature', false);
-
-    app.enabled('some feature')
-    // => false
- });
-
- -

To alter the environment we can set the NODE_ENV environment variable, for example:

- -
$ NODE_ENV=production node app.js
-
- -

This is very important, as many caching mechanisms are only enabled when in production.

- -

Settings

- -

Express supports the following settings out of the box:

- -
    -
  • basepath Application base path used for res.redirect() and transparently handling mounted apps.
  • -
  • views Root views directory defaulting to CWD/views
  • -
  • view engine Default view engine name for views rendered without extensions
  • -
  • view options An object specifying global view options
  • -
  • view cache Enable view caching (enabled in production)
  • -
  • case sensitive routes Enable case-sensitive routing
  • -
  • strict routing When enabled trailing slashes are no longer ignored
  • -
  • jsonp callback Enable res.send() / res.json() transparent jsonp support
  • -
- - -

Routing

- -

Express utilizes the HTTP verbs to provide a meaningful, expressive routing API. -For example we may want to render a user’s account for the path /user/12, this -can be done by defining the route below. The values associated to the named placeholders -are available as req.params.

- -
app.get('/user/:id', function(req, res){
-    res.send('user ' + req.params.id);
-});
-
- -

A route is simple a string which is compiled to a RegExp internally. For example -when /user/:id is compiled, a simplified version of the regexp may look similar to:

- -
\/user\/([^\/]+)\/?
-
- -

Regular expression literals may also be passed for complex uses. Since capture -groups with literal RegExp’s are anonymous we can access them directly req.params. So our first capture group would be req.params[0] and the second would follow as req.params[1].

- -
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
-    res.send(req.params);
-});
-
- -

Curl requests against the previously defined route:

- -
   $ curl http://dev:3000/user
-   [null,null]
-   $ curl http://dev:3000/users
-   [null,null]
-   $ curl http://dev:3000/users/1
-   ["1",null]
-   $ curl http://dev:3000/users/1..15
-   ["1","15"]
-
- -

Below are some route examples, and the associated paths that they -may consume:

- -
 "/user/:id"
- /user/12
-
- "/users/:id?"
- /users/5
- /users
-
- "/files/*"
- /files/jquery.js
- /files/javascripts/jquery.js
-
- "/file/*.*"
- /files/jquery.js
- /files/javascripts/jquery.js
-
- "/user/:id/:operation?"
- /user/1
- /user/1/edit
-
- "/products.:format"
- /products.json
- /products.xml
-
- "/products.:format?"
- /products.json
- /products.xml
- /products
-
- "/user/:id.:format?"
- /user/12
- /user/12.json
-
- -

For example we can POST some json, and echo the json back using the bodyParser middleware which will parse json request bodies (as well as others), and place the result in req.body:

- -
var express = require('express')
-  , app = express.createServer();
-
-app.use(express.bodyParser());
-
-app.post('/', function(req, res){
-  res.send(req.body);
-});
-
-app.listen(3000);
-
- -

Typically we may use a “dumb” placeholder such as “/user/:id” which has no restrictions, however say for example we are limiting a user id to digits, we may use ‘/user/:id([0-9]+)’ which will not match unless the placeholder value contains only digits.

- -

Passing Route Control

- -

We may pass control to the next matching route, by calling the third argument, -the next() function. When a match cannot be made, control is passed back to Connect, -and middleware continue to be invoked in the order that they are added via use(). The same is true for several routes which have the same path defined, they will simply be executed in order until one does not call next() and decides to respond.

- -
app.get('/users/:id?', function(req, res, next){
-    var id = req.params.id;
-    if (id) {
-        // do something
-    } else {
-        next();
-    }
-});
-
-app.get('/users', function(req, res){
-    // do something else
-});
-
- -

The app.all() method is useful for applying the same logic for all HTTP verbs in a single call. Below we use this to load a user from our fake database, and assign it to req.user.

- -
var express = require('express')
-  , app = express.createServer();
-
-var users = [{ name: 'tj' }];
-
-app.all('/user/:id/:op?', function(req, res, next){
-  req.user = users[req.params.id];
-  if (req.user) {
-    next();
-  } else {
-    next(new Error('cannot find user ' + req.params.id));
-  }
-});
-
-app.get('/user/:id', function(req, res){
-  res.send('viewing ' + req.user.name);
-});
-
-app.get('/user/:id/edit', function(req, res){
-  res.send('editing ' + req.user.name);
-});
-
-app.put('/user/:id', function(req, res){
-  res.send('updating ' + req.user.name);
-});
-
-app.get('*', function(req, res){
-  res.send('what???', 404);
-});
-
-app.listen(3000); 
-
- -

Middleware

- -

Middleware via Connect can be -passed to express.createServer() as you would with a regular Connect server. For example:

- -
  var express = require('express');
-
-var app = express.createServer(
-      express.logger()
-    , express.bodyParser()
-  );
-
- -

Alternatively we can use() them which is useful when adding middleware within configure() blocks, in a progressive manor.

- -
app.use(express.logger({ format: ':method :url' }));
-
- -

Typically with connect middleware you would require(‘connect’) like so:

- -
var connect = require('connect');
-app.use(connect.logger());
-app.use(connect.bodyParser());
-
- -

This is somewhat annoying, so express re-exports these middleware properties, however they are identical:

- -
app.use(express.logger());
-app.use(express.bodyParser());
-
- -

Middleware ordering is important, when Connect receives a request the first middleware we pass to createServer() or use() is executed with three parameters, request, response, and a callback function usually named next. When next() is invoked the second middleware will then have it’s turn and so on. This is important to note because many middleware depend on each other, for example methodOverride() checks req.body.method for the HTTP method override, however bodyParser() parses the request body and populates req.body. Another example of this is cookie parsing and session support, we must first use() cookieParser() followed by session()_.

- -

Many Express applications may contain the line app.use(app.router), while this may appear strange, it’s simply the middleware function that contains all defined routes, and performs route lookup based on the current request url and HTTP method. Express allows you to position this middleware, though by default it will be added to the bottom. By positioning the router, we can alter middleware precedence, for example we may want to add error reporting as the last middleware so that any exception passed to next() will be handled by it, or perhaps we want static file serving to have low precedence, allowing our routes to intercept requests to a static file to count downloads etc. This may look a little like below

- -
app.use(express.logger(...));
-app.use(express.bodyParser(...));
-app.use(express.cookieParser(...));
-app.use(express.session(...));
-app.use(app.router);
-app.use(express.static(...));
-app.use(express.errorHandler(...));
-
- -

First we add logger() so that it may wrap node’s req.end() method, providing us with response-time data. Next the request’s body will be parsed (if any), followed by cookie parsing and session support, meaning req.session will be defined by the time we hit our routes in app.router. If a request such as GET /javascripts/jquery.js is handled by our routes, and we do not call next() then the static() middleware will never see this request, however if were to define a route as shown below, we can record stats, refuse downloads, consume download credits etc.

- -
var downloads = {};
-
-app.use(app.router);
-app.use(express.static(__dirname + '/public'));
-
-app.get('/*', function(req, res, next){
-  var file = req.params[0];
-  downloads[file] = downloads[file] || 0;
-  downloads[file]++;
-  next();
-});
-
- -

Route Middleware

- -

Routes may utilize route-specific middleware by passing one or more additional callbacks (or arrays) to the method. This feature is extremely useful for restricting access, loading data used by the route etc.

- -

Typically async data retrieval might look similar to below, where we take the :id parameter, and attempt loading a user.

- -
app.get('/user/:id', function(req, res, next){
-  loadUser(req.params.id, function(err, user){
-    if (err) return next(err);
-    res.send('Viewing user ' + user.name);
-  });
-});
-
- -

To keep things DRY and to increase readability we can apply this logic within a middleware. As you can see below, abstracting this logic into middleware allows us to reuse it, and clean up our route at the same time.

- -
function loadUser(req, res, next) {
-  // You would fetch your user from the db
-  var user = users[req.params.id];
-  if (user) {
-    req.user = user;
-    next();
-  } else {
-    next(new Error('Failed to load user ' + req.params.id));
-  }
-}
-
-app.get('/user/:id', loadUser, function(req, res){
-  res.send('Viewing user ' + req.user.name);
-});
-
- -

Multiple route middleware can be applied, and will be executed sequentially to apply further logic such as restricting access to a user account. In the example below only the authenticated user may edit his/her account.

- -
function andRestrictToSelf(req, res, next) {
-  req.authenticatedUser.id == req.user.id
-    ? next()
-    : next(new Error('Unauthorized'));
-}
-
-app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
-  res.send('Editing user ' + req.user.name);
-});
-
- -

Keeping in mind that middleware are simply functions, we can define function that returns the middleware in order to create a more expressive and flexible solution as shown below.

- -
function andRestrictTo(role) {
-  return function(req, res, next) {
-    req.authenticatedUser.role == role
-      ? next()
-      : next(new Error('Unauthorized'));
-  }
-}
-
-app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
-  res.send('Deleted user ' + req.user.name);
-});
-
- -

Commonly used “stacks” of middleware can be passed as an array (applied recursively), which can be mixed and matched to any degree.

- -
var a = [middleware1, middleware2]
-  , b = [middleware3, middleware4]
-  , all = [a, b];
-
-app.get('/foo', a, function(){});
-app.get('/bar', a, function(){});
-
-app.get('/', a, middleware3, middleware4, function(){});
-app.get('/', a, b, function(){});
-app.get('/', all, function(){});
-
- -

For this example in full, view the route middleware example in the repository.

- -

There are times when we may want to “skip” passed remaining route middleware, but continue matching subsequent routes. To do this we invoke next() with the string “route” next('route'). If no remaining routes match the request url then Express will respond with 404 Not Found.

- -

HTTP Methods

- -

We have seen app.get() a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as app.post(), app.del(), etc.

- -

A common example for POST usage, is when “submitting” a form. Below we simply set our form method to “post” in our html, and control will be given to the route we have defined below it.

- -
 <form method="post" action="/">
-     <input type="text" name="user[name]" />
-     <input type="text" name="user[email]" />
-     <input type="submit" value="Submit" />
- </form>
-
- -

By default Express does not know what to do with this request body, so we should add the bodyParser middleware, which will parse application/x-www-form-urlencoded and application/json request bodies and place the variables in req.body. We can do this by “using” the middleware as shown below:

- -
app.use(express.bodyParser());
-
- -

Our route below will now have access to the req.body.user object which will contain the name and email properties when defined.

- -
app.post('/', function(req, res){
-  console.log(req.body.user);
-  res.redirect('back');
-});
-
- -

When using methods such as PUT with a form, we can utilize a hidden input named _method, which can be used to alter the HTTP method. To do so we first need the methodOverride middleware, which should be placed below bodyParser so that it can utilize it’s req.body containing the form values.

- -
app.use(express.bodyParser());
-app.use(express.methodOverride());
-
- -

The reason that these are not always defaults, is simply because these are not required for Express to be fully functional. Depending on the needs of your application, you may not need these at all, your methods such as PUT and DELETE can still be accessed by clients which can use them directly, although methodOverride provides a great solution for forms. Below shows what the usage of PUT might look like:

- -
<form method="post" action="/">
-  <input type="hidden" name="_method" value="put" />
-  <input type="text" name="user[name]" />
-  <input type="text" name="user[email]" />
-  <input type="submit" value="Submit" />    
-</form>
-
-app.put('/', function(){
-    console.log(req.body.user);
-    res.redirect('back');
-});
-
- -

Error Handling

- -

Express provides the app.error() method which receives exceptions thrown within a route, -or passed to next(err). Below is an example which serves different pages based on our -ad-hoc NotFound exception:

- -
function NotFound(msg){
-  this.name = 'NotFound';
-  Error.call(this, msg);
-  Error.captureStackTrace(this, arguments.callee);
-}
-
-NotFound.prototype.__proto__ = Error.prototype;
-
-app.get('/404', function(req, res){
-  throw new NotFound;
-});
-
-app.get('/500', function(req, res){
-  throw new Error('keyboard cat!');
-});
-
- -

We can call app.error() several times as shown below. -Here we check for an instanceof NotFound and show the -404 page, or we pass on to the next error handler.

- -

Note that these handlers can be defined anywhere, as they -will be placed below the route handlers on listen(). This -allows for definition within configure() blocks so we can -handle exceptions in different ways based on the environment.

- -
app.error(function(err, req, res, next){
-    if (err instanceof NotFound) {
-        res.render('404.jade');
-    } else {
-        next(err);
-    }
-});
-
- -

Here we assume all errors as 500 for the simplicity of -this demo, however you can choose whatever you like. For example when node performs filesystem syscalls, you may receive an error object with the error.code of ENOENT, meaning “no such file or directory”, we can utilize this in our error handling and display a page specific to this if desired.

- -
app.error(function(err, req, res){
-  res.render('500.jade', {
-     error: err
-  });
-});
-
- -

Our apps could also utilize the Connect errorHandler middleware -to report on exceptions. For example if we wish to output exceptions -in “development” mode to stderr we can use:

- -
app.use(express.errorHandler({ dumpExceptions: true }));
-
- -

Also during development we may want fancy html pages to show exceptions -that are passed or thrown, so we can set showStack to true:

- -
app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));
-
- -

The errorHandler middleware also responds with json if Accept: application/json -is present, which is useful for developing apps that rely heavily on client-side JavaScript.

- -

Route Param Pre-conditions

- -

Route param pre-conditions can drastically improve the readability of your application, through implicit loading of data, and validation of request urls. For example if you are constantly fetching common data for several routes, such as loading a user for /user/:id, we might typically do something like below:

- -
app.get('/user/:userId', function(req, res, next){
-  User.get(req.params.userId, function(err, user){
-    if (err) return next(err);
-    res.send('user ' + user.name);
-  });
-}); 
-
- -

With preconditions our params can be mapped to callbacks which may perform validation, coercion, or even loading data from a database. Below we invoke app.param() with the parameter name we wish to map to some middleware, as you can see we receive the id argument which contains the placeholder value. Using this we load the user and perform error handling as usual, and simple call next() to pass control to the next precondition or route handler.

- -
app.param('userId', function(req, res, next, id){
-  User.get(id, function(err, user){
-    if (err) return next(err);
-    if (!user) return next(new Error('failed to find user'));
-    req.user = user;
-    next();
-  });
-});
-
- -

Doing so, as mentioned drastically improves our route readability, and allows us to easily share this logic throughout our application:

- -
app.get('/user/:userId', function(req, res){
-  res.send('user ' + req.user.name);
-});
-
- -

View Rendering

- -

View filenames take the form “<name>.<engine>”, where <engine> is the name -of the module that will be required. For example the view layout.ejs will -tell the view system to require(‘ejs’), the module being loaded must export the method exports.compile(str, options), and return a Function to comply with Express. To alter this behaviour -app.register() can be used to map engines to file extensions, so that for example “foo.html” can be rendered by ejs.

- -

Below is an example using Jade to render index.html, -and since we do not use layout: false the rendered contents of index.jade will be passed as -the body local variable in layout.jade.

- -
app.get('/', function(req, res){
-    res.render('index.jade', { title: 'My Site' });
-});
-
- -

The new view engine setting allows us to specify our default template engine, -so for example when using jade we could set:

- -
app.set('view engine', 'jade');
-
- -

Allowing us to render with:

- -
res.render('index');
-
- -

vs:

- -
res.render('index.jade');
-
- -

When view engine is set, extensions are entirely optional, however we can still -mix and match template engines:

- -
res.render('another-page.ejs');
-
- -

Express also provides the view options setting, which is applied each time a view is rendered, so for example if you rarely use layouts you may set:

- -
app.set('view options', {
-  layout: false
-});
-
- -

Which can then be overridden within the res.render() call if need be:

- -
res.render('myview.ejs', { layout: true });
-
- -

When an alternate layout is required, we may also specify a path. For example if we have view engine set to jade and a file named ./views/mylayout.jade we can simply pass:

- -
res.render('page', { layout: 'mylayout' });
-
- -

Otherwise we must specify the extension:

- -
res.render('page', { layout: 'mylayout.jade' });
-
- -

These paths may also be absolute:

- -
res.render('page', { layout: __dirname + '/../../mylayout.jade' });
-
- -

A good example of this is specifying custom ejs opening and closing tags:

- -
app.set('view options', {
-    open: '{{',
-    close: '}}'
-});
-
- -

View Partials

- -

The Express view system has built-in support for partials and collections, which are “mini” views representing a document fragment. For example rather than iterating -in a view to display comments, we could use partial collection:

- -
partial('comment', { collection: comments });
-
- -

If no other options or local variables are desired, we can omit the object and simply pass our array, which is equivalent to above:

- -
partial('comment', comments);
-
- -

When using the partial collection support a few “magic” locals are provided -for free:

- -
    -
  • firstInCollection true if this is the first object
  • -
  • indexInCollection index of the object in the collection
  • -
  • lastInCollection true if this is the last object
  • -
  • collectionLength length of the collection
  • -
- - -

Local variables passed (or generated) take precedence, however locals passed to the parent view are available in the child view as well. So for example if we were to render a blog post with partial(‘blog/post’, post) it would generate the post local, but the view calling this function had the local user, it would be available to the blog/post view as well.

- -

For documentation on altering the object name view res.partial().

- -

NOTE: be careful about when you use partial collections, as rendering an array with a length of 100 means we have to render 100 views. For simple collections you may inline the iteration instead of using partial collection support to decrease overhead.

- -

View Lookup

- -

View lookup is performed relative to the parent view, for example if we had a page view named views/user/list.jade, and within that view we did partial(‘edit’) it would attempt to load views/user/edit.jade, whereas partial(‘../messages’) would load views/messages.jade.

- -

The view system also allows for index templates, allowing you to have a directory of the same name. For example within a route we may have res.render(‘users’) either views/users.jade, or views/users/index.jade.

- -

When utilizing index views as shown above, we may reference views/users/index.jade from a view in the same directory by partial(‘users’), and the view system will try ../users/index, preventing us from needing to call partial(‘index’).

- -

Template Engines

- -

Below are a few template engines commonly used with Express:

- - - - -

Session Support

- -

Sessions support can be added by using Connect’s session middleware. To do so we also need the cookieParser middleware place above it, which will parse and populate cookie data to req.cookies.

- -
app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat" }));
-
- -

By default the session middleware uses the memory store bundled with Connect, however many implementations exist. For example connect-redis supplies a Redis session store and can be used as shown below:

- -
var RedisStore = require('connect-redis')(express);
-app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
-
- -

Now the req.session and req.sessionStore properties will be accessible to all routes and subsequent middleware. Properties on req.session are automatically saved on a response, so for example if we wish to shopping cart data:

- -
var RedisStore = require('connect-redis')(express);
-app.use(express.bodyParser());
-app.use(express.cookieParser());
-app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));
-
-app.post('/add-to-cart', function(req, res){
-  // Perhaps we posted several items with a form
-  // (use the bodyParser() middleware for this)
-  var items = req.body.items;
-  req.session.items = items;
-  res.redirect('back');
-});
-
-app.get('/add-to-cart', function(req, res){
-  // When redirected back to GET /add-to-cart
-  // we could check req.session.items && req.session.items.length
-  // to print out a message
-  if (req.session.items && req.session.items.length) {
-    req.flash('info', 'You have %s items in your cart', req.session.items.length);
-  }
-  res.render('shopping-cart');
-});
-
- -

The req.session object also has methods such as Session#touch(), Session#destroy(), Session#regenerate() among others to maintain and manipulate sessions. For more information view the Connect Session documentation.

- -

Migration Guide

- -

Express 1.x developers may reference the Migration Guide to get up to speed on how to upgrade your application to work with Express 2.x, Connect 1.x, and Node 0.4.x.

- -

req.header(key[, defaultValue])

- -

Get the case-insensitive request header key, with optional defaultValue:

- -
req.header('Host');
-req.header('host');
-req.header('Accept', '*/*');
-
- -

The Referrer and Referer header fields are special-cased, either will work:

- -
// sent Referrer: http://google.com
-
-req.header('Referer');
-// => "http://google.com"
-
-req.header('Referrer');
-// => "http://google.com"
-
- -

req.accepts(type)

- -

Check if the Accept header is present, and includes the given type.

- -

When the Accept header is not present true is returned. Otherwise -the given type is matched by an exact match, and then subtypes. You -may pass the subtype such as “html” which is then converted internally -to “text/html” using the mime lookup table.

- -
// Accept: text/html
-req.accepts('html');
-// => true
-
-// Accept: text/*; application/json
-req.accepts('html');
-req.accepts('text/html');
-req.accepts('text/plain');
-req.accepts('application/json');
-// => true
-
-req.accepts('image/png');
-req.accepts('png');
-// => false
-
- -

req.is(type)

- -

Check if the incoming request contains the Content-Type -header field, and it contains the give mime type.

- -
   // With Content-Type: text/html; charset=utf-8
-   req.is('html');
-   req.is('text/html');
-   // => true
-
-   // When Content-Type is application/json
-   req.is('json');
-   req.is('application/json');
-   // => true
-
-   req.is('html');
-   // => false
-
- -

Ad-hoc callbacks can also be registered with Express, to perform -assertions again the request, for example if we need an expressive -way to check if our incoming request is an image, we can register “an image” -callback:

- -
    app.is('an image', function(req){
-      return 0 == req.headers['content-type'].indexOf('image');
-    });
-
- -

Now within our route callbacks, we can use to to assert content types -such as “image/jpeg”, “image/png”, etc.

- -
   app.post('/image/upload', function(req, res, next){
-     if (req.is('an image')) {
-       // do something
-     } else {
-       next();
-     }
-   });
-
- -

Keep in mind this method is not limited to checking Content-Type, you -can perform any request assertion you wish.

- -

Wildcard matches can also be made, simplifying our example above for “an image”, by asserting the subtype only:

- -
req.is('image/*');
-
- -

We may also assert the type as shown below, which would return true for “application/json”, and “text/json”.

- -
req.is('*/json');
-
- -

req.param(name[, default])

- -

Return the value of param name when present or default.

- -
    -
  • Checks route params (req.params), ex: /user/:id
  • -
  • Checks query string params (req.query), ex: ?id=12
  • -
  • Checks urlencoded body params (req.body), ex: id=12
  • -
- - -

To utilize urlencoded request bodies, req.body -should be an object. This can be done by using -the _express.bodyParser middleware.

- -

req.get(field, param)

- -

Get field’s param value, defaulting to ‘’ when the param - or field is not present.

- -
 req.get('content-disposition', 'filename');
- // => "something.png"
-
- req.get('Content-Type', 'boundary');
- // => "--foo-bar-baz"
-
- -

req.flash(type[, msg])

- -

Queue flash msg of the given type.

- -
req.flash('info', 'email sent');
-req.flash('error', 'email delivery failed');
-req.flash('info', 'email re-sent');
-// => 2
-
-req.flash('info');
-// => ['email sent', 'email re-sent']
-
-req.flash('info');
-// => []
-
-req.flash();
-// => { error: ['email delivery failed'], info: [] }
-
- -

Flash notification message may also utilize formatters, by default only the %s string formatter is available:

- -
req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);
-
- -

req.isXMLHttpRequest

- -

Also aliased as req.xhr, this getter checks the X-Requested-With header -to see if it was issued by an XMLHttpRequest:

- -
req.xhr
-req.isXMLHttpRequest
-
- -

res.header(key[, val])

- -

Get or set the response header key.

- -
res.header('Content-Length');
-// => undefined
-
-res.header('Content-Length', 123);
-// => 123
-
-res.header('Content-Length');
-// => 123
-
- -

res.charset

- -

Sets the charset for subsequent Content-Type header fields. For example res.send() and res.render() default to “utf8”, so we may explicitly set the charset before rendering a template:

- -
res.charset = 'ISO-8859-1';
-res.render('users');
-
- -

or before responding with res.send():

- -
res.charset = 'ISO-8859-1';
-res.send(str);
-
- -

or with node’s res.end():

- -
res.charset = 'ISO-8859-1';
-res.header('Content-Type', 'text/plain');
-res.end(str);
-
- -

res.contentType(type)

- -

Sets the Content-Type response header to the given type.

- -
  var filename = 'path/to/image.png';
-  res.contentType(filename);
-  // Content-Type is now "image/png"
-
- -

A literal Content-Type works as well:

- -
  res.contentType('application/json');
-
- -

Or simply the extension without leading .:

- -
  res.contentType('json');
-
- -

res.attachment([filename])

- -

Sets the Content-Disposition response header to “attachment”, with optional filename.

- -
  res.attachment('path/to/my/image.png');
-
- -

res.sendfile(path[, options[, callback]])

- -

Used by res.download() to transfer an arbitrary file.

- -
res.sendfile('path/to/my.file');
-
- -

This method accepts an optional callback which is called when -an error occurs, or when the transfer is complete. By default failures call next(err), however when a callback is supplied you must do this explicitly, or act on the error.

- -
res.sendfile(path, function(err){
-  if (err) {
-    next(err);
-  } else {
-    console.log('transferred %s', path);
-  }
-});
-
- -

Options may also be passed to the internal fs.createReadStream() call, for example altering the bufferSize:

- -
res.sendfile(path, { bufferSize: 1024 }, function(err){
-  // handle
-});
-
- -

res.download(file[, filename[, callback[, callback2]]])

- -

Transfer the given file as an attachment with optional alternative filename.

- -
res.download('path/to/image.png');
-res.download('path/to/image.png', 'foo.png');
-
- -

This is equivalent to:

- -
res.attachment(file);
-res.sendfile(file);
-
- -

An optional callback may be supplied as either the second or third argument, which is passed to res.sendfile(). Within this callback you may still respond, as the header has not been sent.

- -
res.download(path, 'expenses.doc', function(err){
-  // handle
-});
-
- -

An optional second callback, callback2 may be given to allow you to act on connection related errors, however you should not attempt to respond.

- -
res.download(path, function(err){
-  // error or finished
-}, function(err){
-  // connection related error
-});
-
- -

res.send(body|status[, headers|status[, status]])

- -

The res.send() method is a high level response utility allowing you to pass -objects to respond with json, strings for html, Buffer instances, or numbers representing the status code. The following are all valid uses:

- -
 res.send(); // 204
- res.send(new Buffer('wahoo'));
- res.send({ some: 'json' });
- res.send('<p>some html</p>');
- res.send('Sorry, cant find that', 404);
- res.send('text', { 'Content-Type': 'text/plain' }, 201);
- res.send(404);
-
- -

By default the Content-Type response header is set, however if explicitly -assigned through res.send() or previously with res.header() or res.contentType() -it will not be set again.

- -

Note that this method end()s the response, so you will want to use node’s res.write() for multiple writes or streaming.

- -

res.json(obj[, headers|status[, status]])

- -

Send a JSON response with optional headers and status. This method - is ideal for JSON-only APIs, however res.send(obj) will send JSON as - well, though not ideal for cases when you want to send for example a string - as JSON, since the default for res.send(string) is text/html.

- -
res.json(null);
-res.json({ user: 'tj' });
-res.json('oh noes!', 500);
-res.json('I dont have that', 404);
-
- -

res.redirect(url[, status])

- -

Redirect to the given url with a default response status of 302.

- -
res.redirect('/', 301);
-res.redirect('/account');
-res.redirect('http://google.com');
-res.redirect('home');
-res.redirect('back');
-
- -

Express supports “redirect mapping”, which by default provides home, and back. -The back map checks the Referrer and Referer headers, while home utilizes -the “basepath” setting and defaults to “/”.

- -

res.cookie(name, val[, options])

- -

Sets the given cookie name to val, with options httpOnly, secure, expires etc. The path option defaults to the app’s “basepath” setting, which -is typically “/”.

- -
// "Remember me" for 15 minutes 
-res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });
-
- -

The maxAge property may be used to set expires relative to Date.now() in milliseconds, so our example above can now become:

- -
res.cookie('rememberme', 'yes', { maxAge: 900000 });
-
- -

To parse incoming Cookie headers, use the cookieParser middleware, which provides the req.cookies object:

- -
app.use(express.cookieParser());
-
-app.get('/', function(req, res){
-  // use req.cookies.rememberme
-});
-
- -

res.clearCookie(name[, options])

- -

Clear cookie name by setting “expires” far in the past. Much like -res.cookie() the path option also defaults to the “basepath” setting.

- -
res.clearCookie('rememberme');
-
- -

res.render(view[, options[, fn]])

- -

Render view with the given options and optional callback fn. -When a callback function is given a response will not be made -automatically, however otherwise a response of 200 and text/html is given.

- -

The options passed are the local variables as well, for example if we want to expose “user” to the view, and prevent a local we do so within the same object:

- -
var user = { name: 'tj' };
-res.render('index', { layout: false, user: user });
-
- -

This options object is also considered an “options” object. For example -when you pass the status local, it’s not only available to the view, it -sets the response status to this number. This is also useful if a template -engine accepts specific options, such as debug, or compress. Below -is an example of how one might render an error page, passing the status for -display, as well as it setting res.statusCode.

- -
 res.render('error', { status: 500, message: 'Internal Server Error' });
-
- -

res.partial(view[, options])

- -

Render view partial with the given options. This method is always available -to the view as a local variable.

- -
    -
  • object the object named by as or derived from the view name
  • -
  • as Variable name for each collection or object value, defaults to the view name.

    - -
      -
    • as: ‘something’ will add the something local variable
    • -
    • as: this will use the collection value as the template context
    • -
    • as: global will merge the collection value’s properties with locals
    • -
    -
  • -
  • collection Array of objects, the name is derived from the view name itself. -For example video.html will have a object video available to it.

  • -
- - -

The following are equivalent, and the name of collection value when passed -to the partial will be movie as derived from the name.

- -
partial('theatre/movie.jade', { collection: movies });
-partial('theatre/movie.jade', movies);
-partial('movie.jade', { collection: movies });
-partial('movie.jade', movies);
-partial('movie', movies);
-// In view: movie.director
-
- -

To change the local from movie to video we can use the “as” option:

- -
partial('movie', { collection: movies, as: 'video' });
-// In view: video.director
-
- -

Also we can make our movie the value of this within our view so that instead -of movie.director we could use this.director.

- -
partial('movie', { collection: movies, as: this });
-// In view: this.director
-
- -

Another alternative is to “expand” the properties of the collection item into -pseudo globals (local variables) by using as: global, which again is syntactic sugar:

- -
partial('movie', { collection: movies, as: global });
-// In view: director
-
- -

This same logic applies to a single partial object usage:

- -
partial('movie', { object: movie, as: this });
-// In view: this.director
-
-partial('movie', { object: movie, as: global });
-// In view: director
-
-partial('movie', { object: movie, as: 'video' });
-// In view: video.director
-
-partial('movie', { object: movie });
-// In view: movie.director
-
- -

When a non-collection (does not have .length) is passed as the second argument, it is assumed to be the object, after which the object’s local variable name is derived from the view name:

- -
var movie = new Movie('Nightmare Before Christmas', 'Tim Burton')
-partial('movie', movie)
-// => In view: movie.director
-
- -

The exception of this, is when a “plain” object, aka “{}” or “new Object” is passed, which is considered an object with local variable. For example some may expect a “movie” local with the following, however since it is a plain object “director” and “title” are simply locals:

- -
var movie = { title: 'Nightmare Before Christmas', director: 'Tim Burton' }; 
-partial('movie', movie)
-
- -

For cases like this where passing a plain object is desired, simply assign it to a key, or use the object key which will use the filename-derived variable name. The examples below are equivalent:

- -
 partial('movie', { locals: { movie: movie }})
- partial('movie', { movie: movie })
- partial('movie', { object: movie })
-
- -

This exact API can be utilized from within a route, to respond with a fragment via Ajax or WebSockets, for example we can render a collection of users directly from a route:

- -
app.get('/users', function(req, res){
-  if (req.xhr) {
-    // respond with the each user in the collection
-    // passed to the "user" view
-    res.partial('user', users);
-  } else {
-    // respond with layout, and users page
-    // which internally does partial('user', users)
-    // along with other UI
-    res.render('users', { users: users });
-  }
-});
-
- -

res.local(name[, val])

- -

Get or set the given local variable name. The locals built up for a response are applied to those given to the view rendering methods such as res.render().

- -
  app.all('/movie/:id', function(req, res, next){
-    Movie.get(req.params.id, function(err, movie){
-      // Assigns res.locals.movie = movie
-      res.local('movie', movie);
-    });
-  });
-
-  app.get('/movie/:id', function(req, res){
-    // movie is already a local, however we
-    // can pass more if we wish
-    res.render('movie', { displayReviews: true });
-  });
-
- -

res.locals(obj)

- -

Assign several locals with the given obj. The following are equivalent:

- -
 res.local('foo', bar);
- res.local('bar', baz);
-
- res.locals({ foo: bar, bar, baz });
-
- -

app.set(name[, val])

- -

Apply an application level setting name to val, or -get the value of name when val is not present:

- -
app.set('views', __dirname + '/views');
-app.set('views');
-// => ...path...
-
- -

Alternatively you may simply access the settings via app.settings:

- -
app.settings.views
-// => ...path...
-
- -

app.enable(name)

- -

Enable the given setting name:

- -
app.enable('some arbitrary setting');
-app.set('some arbitrary setting');
-// => true
-
-app.enabled('some arbitrary setting');
-// => true
-
- -

app.enabled(name)

- -

Check if setting name is enabled:

- -
app.enabled('view cache');
-// => false
-
-app.enable('view cache');
-app.enabled('view cache');
-// => true
-
- -

app.disable(name)

- -

Disable the given setting name:

- -
app.disable('some setting');
-app.set('some setting');
-// => false
-
-app.disabled('some setting');
-// => false
-
- -

app.disabled(name)

- -

Check if setting name is disabled:

- -
app.enable('view cache');
-
-app.disabled('view cache');
-// => false
-
-app.disable('view cache');
-app.disabled('view cache');
-// => true
-
- -

app.configure(env|function[, function])

- -

Define a callback function for the given env (or all environments) with callback function:

- -
app.configure(function(){
-    // executed for each env
-});
-
-app.configure('development', function(){
-    // executed for 'development' only
-});
-
- -

app.redirect(name, val)

- -

For use with res.redirect() we can map redirects at the application level as shown below:

- -
app.redirect('google', 'http://google.com');
-
- -

Now in a route we may call:

- -

res.redirect(‘google’);

- -

We may also map dynamic redirects:

- -
app.redirect('comments', function(req, res){
-  return '/post/' + req.params.id + '/comments';
-});
-
- -

So now we may do the following, and the redirect will dynamically adjust to -the context of the request. If we called this route with GET /post/12 our -redirect Location would be /post/12/comments.

- -
app.get('/post/:id', function(req, res){
-  res.redirect('comments');
-});
-
- -

When mounted, res.redirect() will respect the mount-point. For example if a blog app is mounted at /blog, the following will redirect to /blog/posts:

- -
res.redirect('/posts');
-
- -

app.error(function)

- -

Adds an error handler function which will receive the exception as the first parameter as shown below. -Note that we may set several error handlers by making several calls to this method, however the handler -should call next(err) if it does not wish to deal with the exception:

- -
app.error(function(err, req, res, next){
-  res.send(err.message, 500);
-});
-
- -

app.helpers(obj)

- -

Registers static view helpers.

- -
app.helpers({
-    name: function(first, last){ return first + ', ' + last }
-  , firstName: 'tj'
-  , lastName: 'holowaychuk'
-});
-
- -

Our view could now utilize the firstName and lastName variables, -as well as the name() function exposed.

- -
<%= name(firstName, lastName) %>
-
- -

Express also provides a few locals by default:

- -
- `settings`  the app's settings object
-- `layout(path)`  specify the layout from within a view
-
- -

This method is aliased as app.locals().

- -

app.dynamicHelpers(obj)

- -

Registers dynamic view helpers. Dynamic view helpers -are simply functions which accept req, res, and are -evaluated against the Server instance before a view is rendered. The return value of this function -becomes the local variable it is associated with.

- -
app.dynamicHelpers({
-  session: function(req, res){
-    return req.session;
-  }
-});
-
- -

All views would now have session available so that session data can be accessed via session.name etc:

- -
<%= session.name %>
-
- -

app.lookup

- -

The app.lookup http methods returns an array of callback functions - associated with the given path.

- -

Suppose we define the following routes:

- -
  app.get('/user/:id', function(){});
-  app.put('/user/:id', function(){});
-  app.get('/user/:id/:op?', function(){});
-
- -

We can utilize this lookup functionality to check which routes - have been defined, which can be extremely useful for higher level - frameworks built on Express.

- -
  app.lookup.get('/user/:id');
-  // => [Function]
-
-  app.lookup.get('/user/:id/:op?');
-  // => [Function]
-
-  app.lookup.put('/user/:id');
-  // => [Function]
-
-  app.lookup.all('/user/:id');
-  // => [Function, Function]
-
-  app.lookup.all('/hey');
-  // => []
-
- -

To alias app.lookup.VERB(), we can simply invoke app.VERB() - without a callback, as a shortcut, for example the following are - equivalent:

- -
  app.lookup.get('/user');
-  app.get('/user');
-
- -

Each function returned has the following properties:

- -
  var fn = app.get('/user/:id/:op?')[0];
-
-  fn.regexp
-  // => /^\/user\/(?:([^\/]+?))(?:\/([^\/]+?))?\/?$/i
-
-  fn.keys
-  // => ['id', 'op']
-
-  fn.path
-  // => '/user/:id/:op?'
-
-  fn.method
-  // => 'GET'
-
- -

app.match

- -

The app.match http methods return an array of callback functions - which match the given url, which may include a query string etc. This - is useful when you want reflect on which routes have the opportunity to - respond.

- -

Suppose we define the following routes:

- -
    app.get('/user/:id', function(){});
-    app.put('/user/:id', function(){});
-    app.get('/user/:id/:op?', function(){});
-
- -

Our match against GET will return two functions, since the :op - in our second route is optional.

- -
  app.match.get('/user/1');
-  // => [Function, Function]
-
- -

This second call returns only the callback for /user/:id/:op?.

- -
  app.match.get('/user/23/edit');
-  // => [Function]
-
- -

We can also use all() to disregard the http method:

- -
  app.match.all('/user/20');
-  // => [Function, Function, Function]
-
- -

Each function matched has the following properties:

- -
  var fn = app.match.get('/user/23/edit')[0];
-
-  fn.keys
-  // => ['id', 'op']
-
-  fn.params
-  // => { id: '23', op: 'edit' }
-
-  fn.method
-  // => 'GET'
-
- -

app.mounted(fn)

- -

Assign a callback fn which is called when this Server is passed to Server#use().

- -
var app = express.createServer(),
-    blog = express.createServer();
-
-blog.mounted(function(parent){
-  // parent is app
-  // "this" is blog
-});
-
-app.use(blog);
-
- -

app.register(ext, exports)

- -

Register the given template engine exports -as ext. For example we may wish to map “.html” -files to jade:

- -
 app.register('.html', require('jade'));
-
- -

This is also useful for libraries that may not -match extensions correctly. For example my haml.js -library is installed from npm as “hamljs” so instead -of layout.hamljs, we can register the engine as “.haml”:

- -
 app.register('.haml', require('haml-js'));
-
- -

For engines that do not comply with the Express -specification, we can also wrap their api this way. Below -we map .md to render markdown files, rendering the html once -since it will not change on subsequent calls, and support local substitution -in the form of “{name}”.

- -
  app.register('.md', {
-    compile: function(str, options){
-      var html = md.toHTML(str);
-      return function(locals){
-        return html.replace(/\{([^}]+)\}/g, function(_, name){
-          return locals[name];
-        });
-      };
-    }
-  });
-
- -

app.listen([port[, host]])

- -

Bind the app server to the given port, which defaults to 3000. When host is omitted all -connections will be accepted via INADDR_ANY.

- -
app.listen();
-app.listen(3000);
-app.listen(3000, 'n.n.n.n');
-
- -

The port argument may also be a string representing the path to a unix domain socket:

- -
app.listen('/tmp/express.sock');
-
- -

Then try it out:

- -
$ telnet /tmp/express.sock
-GET / HTTP/1.1
-
-HTTP/1.1 200 OK
-Content-Type: text/plain
-Content-Length: 11
-
-Hello World
-
-
-
- - diff --git a/2x/guide.md b/2x/guide.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/guide.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/images/apps/appetise.png b/2x/images/apps/appetise.png deleted file mode 100644 index d7f9e053..00000000 Binary files a/2x/images/apps/appetise.png and /dev/null differ diff --git a/2x/images/apps/clickdummy.png b/2x/images/apps/clickdummy.png deleted file mode 100644 index 12f9f865..00000000 Binary files a/2x/images/apps/clickdummy.png and /dev/null differ diff --git a/2x/images/apps/developmentseed.png b/2x/images/apps/developmentseed.png deleted file mode 100644 index 7b308d01..00000000 Binary files a/2x/images/apps/developmentseed.png and /dev/null differ diff --git a/2x/images/apps/learnboost.png b/2x/images/apps/learnboost.png deleted file mode 100644 index 07cdec96..00000000 Binary files a/2x/images/apps/learnboost.png and /dev/null differ diff --git a/2x/images/apps/markupio.png b/2x/images/apps/markupio.png deleted file mode 100644 index 97784d77..00000000 Binary files a/2x/images/apps/markupio.png and /dev/null differ diff --git a/2x/images/apps/nodeko.png b/2x/images/apps/nodeko.png deleted file mode 100644 index 93c6d0ce..00000000 Binary files a/2x/images/apps/nodeko.png and /dev/null differ diff --git a/2x/images/apps/opowerjobs.png b/2x/images/apps/opowerjobs.png deleted file mode 100644 index b01d21d4..00000000 Binary files a/2x/images/apps/opowerjobs.png and /dev/null differ diff --git a/2x/images/apps/scrabbly.png b/2x/images/apps/scrabbly.png deleted file mode 100644 index f8b2f890..00000000 Binary files a/2x/images/apps/scrabbly.png and /dev/null differ diff --git a/2x/images/apps/storify.png b/2x/images/apps/storify.png deleted file mode 100644 index e3adb547..00000000 Binary files a/2x/images/apps/storify.png and /dev/null differ diff --git a/2x/images/apps/toptwittertrends.png b/2x/images/apps/toptwittertrends.png deleted file mode 100644 index 37f269b5..00000000 Binary files a/2x/images/apps/toptwittertrends.png and /dev/null differ diff --git a/2x/images/apps/widescript.png b/2x/images/apps/widescript.png deleted file mode 100644 index 72102b89..00000000 Binary files a/2x/images/apps/widescript.png and /dev/null differ diff --git a/2x/images/bg.jpg b/2x/images/bg.jpg deleted file mode 100644 index d2e3b085..00000000 Binary files a/2x/images/bg.jpg and /dev/null differ diff --git a/2x/images/bg.tile.jpg b/2x/images/bg.tile.jpg deleted file mode 100644 index 5efe6a3d..00000000 Binary files a/2x/images/bg.tile.jpg and /dev/null differ diff --git a/2x/images/logo.png b/2x/images/logo.png deleted file mode 100644 index 53a747e9..00000000 Binary files a/2x/images/logo.png and /dev/null differ diff --git a/2x/images/top.png b/2x/images/top.png deleted file mode 100644 index 38fbe504..00000000 Binary files a/2x/images/top.png and /dev/null differ diff --git a/2x/index.html b/2x/index.html deleted file mode 100644 index b65d5e0f..00000000 --- a/2x/index.html +++ /dev/null @@ -1,287 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to use the latest version of Express.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -
var app = express.createServer();
-
-app.get('/', function(req, res){
-    res.send('Hello World');
-});
-
-app.listen(3000);
-
- -

Features

- -
    -
  • Robust routing
  • -
  • Redirection helpers
  • -
  • Dynamic view helpers
  • -
  • Application level view options
  • -
  • Content negotiation
  • -
  • Application mounting
  • -
  • Focus on high performance
  • -
  • View rendering and partials support
  • -
  • Environment based configuration
  • -
  • Session based flash notifications
  • -
  • Built on Connect
  • -
  • Executable for generating applications quickly
  • -
  • High test coverage
  • -
- - -

Contributors

- -

The following are the major contributors of Express (in no specific order).

- - - - -

Third-Party Modules

- -

The following modules complement or extend Express directly:

- - - - -

More Information

- - - -
-
- - diff --git a/2x/index.md b/2x/index.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/index.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/layout/foot.html b/2x/layout/foot.html deleted file mode 100644 index 066f1158..00000000 --- a/2x/layout/foot.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
- - diff --git a/2x/layout/head.html b/2x/layout/head.html deleted file mode 100644 index 5e7d2b56..00000000 --- a/2x/layout/head.html +++ /dev/null @@ -1,206 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -

- High performance, high class web development for - Node.js -

- diff --git a/2x/migrate.html b/2x/migrate.html deleted file mode 100644 index ff43f676..00000000 --- a/2x/migrate.html +++ /dev/null @@ -1,418 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -

Express 1.x to 2.x Migration

- -

HTTPS

- -

Creating an HTTPS server is simply, simply pass the TLS options to express.createServer():

- -
 var app = express.createServer({
-     key: ...
-   , cert: ...
- });
-
- app.listen(443);
-
- -

req.header() Referrer

- -

Previously if anyone was doing something similar to:

- -
 req.headers.referrer || req.headers.referer
- req.header('Referrer') || req.header('Referer')
-
- -

With the new special-case we may now simply use Referrer which will return either if defined:

- -
 req.header('Referrer')
-
- -

res.local(name, val)

- -

Previously all local variables had to be passed to res.render(), or either app.helpers() or app.dynamicHelpers(), now we may do this at the request-level progressively. The res.local() method accepts a name and val, however the locals passed to res.render() will take precedence.

- -

For example we may utilize this feature to create locals in middleware:

- -
 function loadUser(req, res, next) {
-   User.get(req.params.id, function(err, user){
-     res.local('user', user);
-     next();
-   });
- }
-
- app.get('/user/:id', loadUser, function(req, res){
-   res.render('user');
- });
-
- -

req.param(name[, defaultValue])

- -

Previously only name was accepted, so some of you may have been doing the following:

- -
 var id = req.param('id') || req.user.id;
-
- -

The new defaultValue argument can handle this nicely:

- -
 var id = req.param('id', req.user.id);
-
- -

app.helpers() / app.locals()

- -

app.locals() is now an alias of app.helpers(), as helpers makes more sense for functions.

- -

req.accepts(type)

- -

req.accepts() now accepts extensions:

- -
  // Accept: text/html
-  req.accepts('html');
-  req.accepts('.html');
-  // => true
-
-  // Accept: text/*; application/json
-  req.accepts('html');
-  req.accepts('text/*');
-  req.accepts('text/plain');
-  req.accepts('application/json');
-  // => true
-
-  req.accepts('image/png');
-  req.accepts('png');
-  // => false
-
- -

res.cookie()

- -

Previously only directly values could be passed, so for example:

- -
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000) });
-
- -

However now we have the alternative maxAge property which may be used to set expires relative to Date.now() in milliseconds, so our example above can now become:

- -
res.cookie('rememberme', 'yes', { maxAge: 900000 });
-
- -

res.download() / res.sendfile()

- -

Both of these methods now utilize Connect’s static file server behind the scenes (actually the previous Express code was ported to Connect 1.0). With this change comes a change to the callback as well. Previously the path and stream were passed, however now only an error is passed, when no error has occurred the callback will be invoked indicating that the file transfer is complete. The callback remains optional:

- -
 res.download('/path/to/file');
-
- res.download('/path/to/file', function(err){
-   if (err) {
-     console.error(err);
-   } else {
-     console.log('transferred');
-   }
- });
-
- -

The stream threshold setting was removed.

- -

res.render()

- -

Previously locals were passed as a separate key:

- -
 res.render('user', { layout: false, locals: { user: user }});
-
- -

In Express 2.0 both the locals and the options are one in the same, meaning you cannot have a local variable named layout as it is reserved for express, however this cleans up the API:

- -
 res.render('user', { layout: false, user: user });
-
- -

res.partial()

- -

Express 2.0 adds the res.partial() method, helpful for rendering partial fragments over WebSockets or Ajax requests etc. The API is identical to the partial() calls within views.

- -
 // render a collection of comments
- res.partial('comment', [comment1, comment2]); 
-
- // render a single comment
- res.partial('comment', comment);
-
- -

partial() locals

- -

Both res.partial() and the partial() functions accept a single object consisting of both the options and the locals. Previously with Express 1.x you may pass user to a partial, along with date like so:

- -
   partial('user', { object: user, locals: { date: new Date }})
-
- -

or perhaps if you preferred not to use the inferred name user you may used a local for this as well:

- -
   partial('user', { locals: { user: user, date: new Date }})
-
- -

With recent changes to Express 2.x the object passed is now both, so the following is valid for the object option and locals:

- -
   partial('user', { object: user, date: new Date })
-
- -

Or the following which is equivalent, however the local var name is explicitly set to user instead of deduced from the filename.

- -
   partial('user', { user: user, date: new Date })
-
- -

When a “basic” object aka {} or new Object is passed, it is considered options, otherwise it is considered the object. The following are equivalent:

- -
  partial('user', user); 
-  partial('user', { object: user }); 
-
- -

Template Engine Compliance

- -

To comply with Express previously engines needed the following signature:

- -
 engine.render(str, options, function(err){});
-
- -

Now they must export a compile() function, returning a function which when called with local variables will render the template. This allows Express to cache the compiled function in memory during production.

- -
 var fn = engine.compile(str, options);
- fn(locals);
-
- -

View Partial Lookup

- -

Previously partials were loaded relative to the now removed view partials directory setting, or by default views/partials, now they are relative to the view calling them, read more on view lookup.

- -

Mime Types

- -

Express and Connect now utilize the mime module in npm, so to add more use:

- -
 require('mime').define({ 'foo/bar': ['foo', 'bar'] });
-
- -

static() middleware

- -

Previously named staticProvider(), the now static() middleware takes a single directory path, followed by options.

- -
 app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
-
- -

Previously when using options the root option would be used for this:

- -
 app.use(express.staticProvider({ root: __dirname + '/public', maxAge: oneYear }));
-
-
-
- - diff --git a/2x/migrate.md b/2x/migrate.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/migrate.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/2x/screencasts.html b/2x/screencasts.html deleted file mode 100644 index 313ef041..00000000 --- a/2x/screencasts.html +++ /dev/null @@ -1,248 +0,0 @@ - - - Express - node web framework - - - - - - - - - Fork me on GitHub - -
-
- -
-
Express 2.x IS END-OF-LIFE AND NO LONGER MAINTAINED
-

Known and unknown security and performance issues in 2.x have not been addressed since the last update (29 June, 2012). It is highly recommended to upgrade to Express 3.x or to Express 4.x.

-

If you are unable to upgrade past 2.x, please consider Commercial Support Options.

-
-

- High performance, high class web development for - Node.js -

- -

Introduction

- -

This introduction screencast covers the basics of Express, and how to get started with your first application.

- - - - -

View Partials

- -

In this screencast we work with partials to display a collection of users using the Jade template engine, and learn about view path resolution.

- - - - -

Route Specific Middleware

- -

In the screencast below we learn about the benefits of route-specific middleware.

- - - - -

Route Param Preconditions

- -

Learn about route parameter (/user/:id) pre-conditions, providing automated validation, and loading of data via the named route param segments.

- - - -
-
- - diff --git a/2x/screencasts.md b/2x/screencasts.md new file mode 100644 index 00000000..789454e9 --- /dev/null +++ b/2x/screencasts.md @@ -0,0 +1,4 @@ +--- +redirect_to: + - https://github.com/expressjs/expressjs.com/tree/2x +--- \ No newline at end of file diff --git a/de/support/index.md b/de/support/index.md index 48788aba..f2751481 100644 --- a/de/support/index.md +++ b/de/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/en/support/index.md b/en/support/index.md index dc2d120c..4c65386f 100644 --- a/en/support/index.md +++ b/en/support/index.md @@ -17,7 +17,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/es/support/index.md b/es/support/index.md index e335d652..722b879b 100644 --- a/es/support/index.md +++ b/es/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/fr/support/index.md b/fr/support/index.md index df1d3e6e..863175e9 100644 --- a/fr/support/index.md +++ b/fr/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/id/support/index.md b/id/support/index.md index 583125c7..5b378d76 100644 --- a/id/support/index.md +++ b/id/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .no-release }](/{{page.lang}}/5x/api.html) | **not yet released**{: .no-release } | **not yet released**{: .no-release } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | March 2011 | July 2012 | | **v1.x**{: .eol } | December 2010 | March 2011 | | **v0.14.x**{: .eol } | December 2010 | December 2010 | diff --git a/it/support/index.md b/it/support/index.md index 0a4a51d8..6248f702 100644 --- a/it/support/index.md +++ b/it/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/ja/support/index.md b/ja/support/index.md index 45843448..21daf14e 100644 --- a/ja/support/index.md +++ b/ja/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/ko/support/index.md b/ko/support/index.md index 5cf164e9..78566be9 100644 --- a/ko/support/index.md +++ b/ko/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/pt-br/support/index.md b/pt-br/support/index.md index ae7b270c..5b609f7e 100644 --- a/pt-br/support/index.md +++ b/pt-br/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/ru/support/index.md b/ru/support/index.md index da575e42..d72aa1ff 100644 --- a/ru/support/index.md +++ b/ru/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/sk/support/index.md b/sk/support/index.md index a38a7240..804ee2f7 100644 --- a/sk/support/index.md +++ b/sk/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/th/support/index.md b/th/support/index.md index a576c469..1d665737 100644 --- a/th/support/index.md +++ b/th/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/tr/support/index.md b/tr/support/index.md index 44de09f6..5cb40690 100644 --- a/tr/support/index.md +++ b/tr/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/uk/support/index.md b/uk/support/index.md index 42933cad..a8e3a3a3 100644 --- a/uk/support/index.md +++ b/uk/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/uz/support/index.md b/uz/support/index.md index 639576a4..115b4887 100644 --- a/uz/support/index.md +++ b/uz/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/zh-cn/support/index.md b/zh-cn/support/index.md index b3c8076c..b0019d72 100644 --- a/zh-cn/support/index.md +++ b/zh-cn/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 | diff --git a/zh-tw/support/index.md b/zh-tw/support/index.md index 64683f95..08eee636 100644 --- a/zh-tw/support/index.md +++ b/zh-tw/support/index.md @@ -16,7 +16,7 @@ Versions that are EOL (end-of-life) _may_ receive updates for critical security | [**v5.x**{: .supported }](/{{page.lang}}/5x/api.html) | 18 | September 2024 | **ongoing**{: .supported } | | [**v4.x**{: .supported }](/{{page.lang}}/4x/api.html) | 0.10.0 | April 2014 | **ongoing**{: .supported } | | [**v3.x**{: .eol }](/{{page.lang}}/3x/api.html) | 0.8.0 | October 2012 | July 2015 | -| [**v2.x**{: .eol }](/{{page.lang}}/2x/) | 0.4.1 | March 2011 | July 2012 | +| [**v2.x**{: .eol }](/2x/) | 0.4.1 | March 2011 | July 2012 | | **v1.x**{: .eol } | 0.2.0 | December 2010 | March 2011 | | **v0.14.x**{: .eol } | 0.1.98 | December 2010 | December 2010 |