Comparar commits
69 Commits
3.0.0alpha1
..
2.5.2
| Autor | SHA1 | Data | |
|---|---|---|---|
| 380a6c5363 | |||
| c047b64ab5 | |||
| ae2bcb2615 | |||
| 02cdf0c72b | |||
| a7520ad00c | |||
| bf7807619d | |||
| b5346005af | |||
| 334a8d3fa2 | |||
| 7c6c07497a | |||
| 95f6cda9c4 | |||
| e2de941d09 | |||
| f7d67ce766 | |||
| b63f2ca903 | |||
| 77c2d89be6 | |||
| 458097fe7b | |||
| 1b25240d36 | |||
| 1cce4d98ff | |||
| 09b5c79073 | |||
| 9348500366 | |||
| 0f6a044d98 | |||
| 049a557341 | |||
| 94a6f42efd | |||
| a4aed5f51a | |||
| 3e6f45cb72 | |||
| 3bd4de7f73 | |||
| 5c04f85f93 | |||
| 77f885d4a0 | |||
| c2fc9a83e8 | |||
| d8b20bd2d5 | |||
| d3c4fd91c9 | |||
| 00e44f6fc9 | |||
| 6692f911ab | |||
| 4f0b3f4684 | |||
| cbf330c3db | |||
| 13010987b0 | |||
| b078481cdb | |||
| 3888468a96 | |||
| a6b70ceca4 | |||
| 45757a0f1a | |||
| 24a4a80ccd | |||
| 2fdd906a41 | |||
| 71cc6bac22 | |||
| 3a46660932 | |||
| adca07a858 | |||
| 6b924bf1df | |||
| eb88f160b6 | |||
| 01e6df759e | |||
| 1dc4e6fcb4 | |||
| fff6951d94 | |||
| 1ebd49af75 | |||
| 8c2107e337 | |||
| cddc5442f1 | |||
| ac8cb270fe | |||
| d54ee58f93 | |||
| ce0fa0a3b2 | |||
| e2f41147ed | |||
| af3f7f0a65 | |||
| a37003945b | |||
| 75361fb177 | |||
| 21f9b386db | |||
| 271cb16ecd | |||
| 803ec213d7 | |||
| 9e9042f1eb | |||
| ec4c86f46d | |||
| 45f22ec602 | |||
| 0e1eb72058 | |||
| 4690b6cdf2 | |||
| 22204a5ce1 | |||
| 1ec16c0450 |
+1
-5
@@ -1,4 +1,3 @@
|
||||
coverage.html
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
@@ -10,9 +9,6 @@ lib-cov
|
||||
*.swp
|
||||
*.swo
|
||||
benchmarks/graphs
|
||||
testing
|
||||
testing.js
|
||||
node_modules/
|
||||
testing
|
||||
.coverage_data
|
||||
cover_html
|
||||
test.js
|
||||
|
||||
@@ -5,4 +5,3 @@ support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
coverage.html
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
+38
-1
@@ -1,10 +1,47 @@
|
||||
|
||||
2.5.2 / 2011-12-10
|
||||
==================
|
||||
|
||||
* Fixed: express(1) LF -> CRLF for windows
|
||||
|
||||
2.5.1 / 2011-11-17
|
||||
==================
|
||||
|
||||
* Changed: updated connect to 1.8.x
|
||||
* Removed sass.js support from express(1)
|
||||
|
||||
2.5.0 / 2011-10-24
|
||||
==================
|
||||
|
||||
* Added ./routes dir for generated app by default
|
||||
* Added npm install reminder to express(1) app gen
|
||||
* Added 0.5.x support
|
||||
* Removed `make test-cov` since it wont work with node 0.5.x
|
||||
* Fixed express(1) public dir for windows. Closes #866
|
||||
|
||||
2.4.7 / 2011-10-05
|
||||
==================
|
||||
|
||||
* Added mkdirp to express(1). Closes #795
|
||||
* Added simple _json-config_ example
|
||||
* Added shorthand for the parsed request's pathname via `req.path`
|
||||
* Changed connect dep to 1.7.x to fix npm issue...
|
||||
* Fixed `res.redirect()` __HEAD__ support. [reported by xerox]
|
||||
* Fixed `req.flash()`, only escape args
|
||||
* Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie]
|
||||
|
||||
2.4.6 / 2011-08-22
|
||||
==================
|
||||
|
||||
* Fixed multiple param callback regression. Closes #824 [reported by TroyGoode]
|
||||
|
||||
2.4.5 / 2011-08-19
|
||||
==================
|
||||
|
||||
* Added support for routes to handle errors. Closes #809
|
||||
* Added `app.routes.all()`. Closes #803
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc. * Refactored `Route` to use a single array of callbacks
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc.
|
||||
* Refactored `Route` to use a single array of callbacks
|
||||
* Added support for multiple callbacks for `app.param()`. Closes #801
|
||||
Closes #805
|
||||
* Changed: removed .call(self) for route callbacks
|
||||
|
||||
+22
-12
@@ -1,19 +1,29 @@
|
||||
|
||||
REPORTER = dot
|
||||
DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS = $(DOCS:.md=.html)
|
||||
TESTS = $(shell find test/*.test.js)
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER)
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso $(TESTS)
|
||||
|
||||
test-acceptance:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter spec \
|
||||
test/acceptance/*.js
|
||||
docs: $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@./support/toc.js docs/guide.html
|
||||
|
||||
test-cov: lib-cov
|
||||
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
|
||||
%.html: %.md
|
||||
@echo "... $< -> $@"
|
||||
@markdown $< \
|
||||
| cat docs/layout/head.html - docs/layout/foot.html \
|
||||
> $@
|
||||
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
site:
|
||||
rm -fr /tmp/docs \
|
||||
&& cp -fr docs /tmp/docs \
|
||||
&& git checkout gh-pages \
|
||||
&& cp -fr /tmp/docs/* . \
|
||||
&& echo "done"
|
||||
|
||||
.PHONY: site test test-acceptance
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: site test docs docclean
|
||||
+67
-100
@@ -1,20 +1,23 @@
|
||||
|
||||

|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
```js
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
# Express
|
||||
|
||||
Insanely fast (and small) server-side JavaScript web development framework
|
||||
built on [node](http://nodejs.org) and [Connect](http://github.com/senchalabs/connect).
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
## Installation
|
||||
|
||||
$ npm install express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Quick Start
|
||||
@@ -28,55 +31,83 @@ app.listen(3000);
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install
|
||||
$ npm install -d
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app
|
||||
$ node app.js
|
||||
|
||||
## Features
|
||||
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* Robust routing
|
||||
* HTTP helpers (redirection, caching, etc)
|
||||
* View system supporting 14+ template engines
|
||||
* Redirection helpers
|
||||
* Dynamic view helpers
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* View rendering and partials support
|
||||
* Environment based configuration
|
||||
* Executable for generating applications quickly
|
||||
* Session based flash notifications
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* High test coverage
|
||||
* Executable for generating applications quickly
|
||||
* Application level view options
|
||||
|
||||
## Philosophy
|
||||
Via Connect:
|
||||
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](github.com/visionmedia/consolidate.js) you
|
||||
can quickly craft your perfect framework.
|
||||
* Session support
|
||||
* Cache API
|
||||
* Mime helpers
|
||||
* ETag support
|
||||
* Persistent flash notifications
|
||||
* Cookie support
|
||||
* JSON-RPC
|
||||
* Logging
|
||||
* and _much_ more!
|
||||
|
||||
## Contributors
|
||||
|
||||
The following are the major contributors of Express (in no specific order).
|
||||
|
||||
* TJ Holowaychuk ([visionmedia](http://github.com/visionmedia))
|
||||
* Ciaran Jessup ([ciaranj](http://github.com/ciaranj))
|
||||
* Aaron Heckmann ([aheckmann](http://github.com/aheckmann))
|
||||
* Guillermo Rauch ([guille](http://github.com/guille))
|
||||
|
||||
## More Information
|
||||
|
||||
* Join #express on freenode
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* #express on freenode
|
||||
* [express-expose](http://github.com/visionmedia/express-expose) expose objects, functions, modules and more to client-side js with ease
|
||||
* [express-configure](http://github.com/visionmedia/express-configuration) async configuration support
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash notification rendering helper
|
||||
* [express-namespace](http://github.com/visionmedia/express-namespace) namespaced route support
|
||||
* [express-params](https://github.com/visionmedia/express-params) param pre-condition functions
|
||||
* [express-mongoose](https://github.com/LearnBoost/express-mongoose) plugin for easy rendering of Mongoose async Query results
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
* Screencast - [Introduction](http://bit.ly/eRYu0O)
|
||||
* Screencast - [View Partials](http://bit.ly/dU13Fx)
|
||||
* Screencast - [Route Specific Middleware](http://bit.ly/hX4IaH)
|
||||
* Screencast - [Route Path Placeholder Preconditions](http://bit.ly/eNqmVs)
|
||||
|
||||
## Node Compatibility
|
||||
|
||||
Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
|
||||
Express 2.x is compatible with node 0.4.x or 0.6.x, and connect 1.x
|
||||
|
||||
Express 3.x (master) will be compatible with node 0.6.x and connect 2.x
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
$ cd express
|
||||
$ npm install -d
|
||||
$ npm install
|
||||
|
||||
then run whichever tests you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
$ node examples/jade/app.js
|
||||
|
||||
## Running Tests
|
||||
|
||||
@@ -88,75 +119,11 @@ then run the tests:
|
||||
|
||||
$ make test
|
||||
|
||||
## Contributors
|
||||
|
||||
```
|
||||
project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
2 Randy Merrill 0.1%
|
||||
2 Benny Wong 0.1%
|
||||
2 Hunter Loftis 0.1%
|
||||
2 Jake Gordon 0.1%
|
||||
2 Brian McKinney 0.1%
|
||||
2 Roman Shtylman 0.1%
|
||||
2 Ben Weaver 0.1%
|
||||
2 Dave Hoover 0.1%
|
||||
2 Eivind Fjeldstad 0.1%
|
||||
2 Daniel Shaw 0.1%
|
||||
1 Matt Colyer 0.0%
|
||||
1 Pau Ramon 0.0%
|
||||
1 Pero Pejovic 0.0%
|
||||
1 Peter Rekdal Sunde 0.0%
|
||||
1 Raynos 0.0%
|
||||
1 Teng Siong Ong 0.0%
|
||||
1 Viktor Kelemen 0.0%
|
||||
1 ctide 0.0%
|
||||
1 8bitDesigner 0.0%
|
||||
1 isaacs 0.0%
|
||||
1 mgutz 0.0%
|
||||
1 pikeas 0.0%
|
||||
1 shuwatto 0.0%
|
||||
1 tstrimple 0.0%
|
||||
1 ewoudj 0.0%
|
||||
1 Adam Sanderson 0.0%
|
||||
1 Andrii Kostenko 0.0%
|
||||
1 Andy Hiew 0.0%
|
||||
1 Arpad Borsos 0.0%
|
||||
1 Ashwin Purohit 0.0%
|
||||
1 Benjen 0.0%
|
||||
1 Darren Torpey 0.0%
|
||||
1 Greg Ritter 0.0%
|
||||
1 Gregory Ritter 0.0%
|
||||
1 James Herdman 0.0%
|
||||
1 Jim Snodgrass 0.0%
|
||||
1 Joe McCann 0.0%
|
||||
1 Jonathan Dumaine 0.0%
|
||||
1 Jonathan Palardy 0.0%
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2012 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
+163
-135
@@ -4,37 +4,49 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../')
|
||||
var fs = require('fs')
|
||||
, exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, os = require('os')
|
||||
, fs = require('fs');
|
||||
, mkdirp = require('mkdirp');
|
||||
|
||||
// CLI
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
program
|
||||
.version(express.version)
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
|
||||
.option('-f, --force', 'force on non-empty directory')
|
||||
.parse(process.argv);
|
||||
var version = '2.5.2';
|
||||
|
||||
// Path
|
||||
/**
|
||||
* Add session support.
|
||||
*/
|
||||
|
||||
var path = program.args.shift() || '.';
|
||||
var sessions = false;
|
||||
|
||||
// end-of-line code
|
||||
/**
|
||||
* CSS engine to utilize.
|
||||
*/
|
||||
|
||||
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
|
||||
var cssEngine;
|
||||
|
||||
// Template engine
|
||||
/**
|
||||
* Template engine to utilize.
|
||||
*/
|
||||
|
||||
program.template = 'jade';
|
||||
if (program.ejs) program.template = 'ejs';
|
||||
if (program.jshtml) program.template = 'jshtml';
|
||||
var templateEngine = 'jade';
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
|
||||
var usage = ''
|
||||
+ '\n'
|
||||
+ ' Usage: express [options] [path]\n'
|
||||
+ '\n'
|
||||
+ ' Options:\n'
|
||||
+ ' -s, --sessions add session support\n'
|
||||
+ ' -t, --template <engine> add template <engine> support (jade|ejs). default=jade\n'
|
||||
+ ' -c, --css <engine> add stylesheet <engine> support (stylus). default=plain css\n'
|
||||
+ ' -v, --version output framework version\n'
|
||||
+ ' -h, --help output help information\n'
|
||||
;
|
||||
|
||||
/**
|
||||
* Routes index template.
|
||||
@@ -47,9 +59,9 @@ var index = [
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' });'
|
||||
, ' res.render(\'index\', { title: \'Express\' })'
|
||||
, '};'
|
||||
].join(eol);
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
@@ -61,27 +73,23 @@ var jadeLayout = [
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body'
|
||||
, ' block content'
|
||||
].join(eol);
|
||||
, ' body!= body'
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'extends layout'
|
||||
, ''
|
||||
, 'block content'
|
||||
, ' h1= title'
|
||||
, ' p Welcome to #{title}'
|
||||
].join(eol);
|
||||
'h1= title'
|
||||
, 'p Welcome to #{title}'
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
* EJS layout template.
|
||||
*/
|
||||
|
||||
var ejsIndex = [
|
||||
var ejsLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
@@ -89,37 +97,19 @@ var ejsIndex = [
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <h1><%= title %></h1>'
|
||||
, ' <p>Welcome to <%= title %></p>'
|
||||
, ' <%- body %>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* JSHTML layout template.
|
||||
* EJS index template.
|
||||
*/
|
||||
|
||||
var jshtmlLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title> @write(title) </title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' @write(body)'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML index template.
|
||||
*/
|
||||
|
||||
var jshtmlIndex = [
|
||||
'<h1>@write(title)</h1>'
|
||||
, '<p>Welcome to @write(title)</p>'
|
||||
].join(eol);
|
||||
var ejsIndex = [
|
||||
'<h1><%= title %></h1>'
|
||||
, '<p>Welcome to <%= title %></p>'
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
@@ -134,22 +124,7 @@ var css = [
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
*/
|
||||
|
||||
var less = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
@@ -161,7 +136,7 @@ var stylus = [
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color: #00B7FF'
|
||||
].join(eol);
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* App template.
|
||||
@@ -175,41 +150,83 @@ var app = [
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , http = require(\'http\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, 'var app = module.exports = express.createServer();'
|
||||
, ''
|
||||
, '// Configuration'
|
||||
, ''
|
||||
, 'app.configure(function(){'
|
||||
, ' app.set(\'views\', __dirname + \'/views\');'
|
||||
, ' app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, ' app.use(express.favicon());'
|
||||
, ' app.use(express.logger(\'dev\'));{css}'
|
||||
, ' app.use(express.static(__dirname + \'/public\'));'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}'
|
||||
, ' app.use(express.methodOverride());{sess}{css}'
|
||||
, ' app.use(app.router);'
|
||||
, ' app.use(express.static(__dirname + \'/public\'));'
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'development\', function(){'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
|
||||
, '});'
|
||||
, ''
|
||||
, 'app.configure(\'production\', function(){'
|
||||
, ' app.use(express.errorHandler()); '
|
||||
, '});'
|
||||
, ''
|
||||
, '// Routes'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, ''
|
||||
, 'http.createServer(app).listen(3000);'
|
||||
, 'app.listen(3000);'
|
||||
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
|
||||
, ''
|
||||
, 'console.log("Express server listening on port 3000");'
|
||||
, ''
|
||||
].join(eol);
|
||||
].join('\r\n');
|
||||
|
||||
// Parse arguments
|
||||
|
||||
var args = process.argv.slice(2)
|
||||
, path = '.';
|
||||
|
||||
while (args.length) {
|
||||
var arg = args.shift();
|
||||
switch (arg) {
|
||||
case '-h':
|
||||
case '--help':
|
||||
abort(usage);
|
||||
break;
|
||||
case '-v':
|
||||
case '--version':
|
||||
abort(version);
|
||||
break;
|
||||
case '-s':
|
||||
case '--session':
|
||||
case '--sessions':
|
||||
sessions = true;
|
||||
break;
|
||||
case '-c':
|
||||
case '--css':
|
||||
args.length
|
||||
? (cssEngine = args.shift())
|
||||
: abort('--css requires an argument');
|
||||
break;
|
||||
case '-t':
|
||||
case '--template':
|
||||
args.length
|
||||
? (templateEngine = args.shift())
|
||||
: abort('--template requires an argument');
|
||||
break;
|
||||
default:
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
emptyDirectory(path, function(empty){
|
||||
if (empty || program.force) {
|
||||
if (empty) {
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
program.confirm('destination is not empty, continue? ', function(ok){
|
||||
confirm('destination is not empty, continue? ', function(ok){
|
||||
if (ok) {
|
||||
process.stdin.destroy();
|
||||
createApplicationAt(path);
|
||||
@@ -231,11 +248,8 @@ function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
console.log(' run the app:');
|
||||
console.log(' $ node app');
|
||||
console.log(' dont forget to install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
});
|
||||
|
||||
@@ -244,10 +258,7 @@ function createApplicationAt(path) {
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
write(path + '/public/stylesheets/style.less', less);
|
||||
break;
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
@@ -261,67 +272,49 @@ function createApplicationAt(path) {
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (program.template) {
|
||||
switch (templateEngine) {
|
||||
case 'ejs':
|
||||
write(path + '/views/layout.ejs', ejsLayout);
|
||||
write(path + '/views/index.ejs', ejsIndex);
|
||||
break;
|
||||
case 'jade':
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
break;
|
||||
case 'jshtml':
|
||||
write(path + '/views/layout.jshtml', jshtmlLayout);
|
||||
write(path + '/views/index.jshtml', jshtmlIndex);
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
switch (cssEngine) {
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
app = app.replace('{css}', '\r\n app.use(require(\'stylus\').middleware({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
|
||||
app = app.replace('{sess}', sessions
|
||||
? '\r\n app.use(express.cookieParser());\r\n app.use(express.session({ secret: \'your secret here\' }));'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', program.template);
|
||||
app = app.replace(':TEMPLATE', templateEngine);
|
||||
|
||||
// package.json
|
||||
var pkg = {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app' }
|
||||
, dependencies: {
|
||||
express: express.version
|
||||
}
|
||||
}
|
||||
var json = '{\r\n';
|
||||
json += ' "name": "application-name"\r\n';
|
||||
json += ' , "version": "0.0.1"\r\n';
|
||||
json += ' , "private": true\r\n';
|
||||
json += ' , "dependencies": {\r\n';
|
||||
json += ' "express": "' + version + '"\r\n';
|
||||
if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\r\n';
|
||||
if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\r\n';
|
||||
json += ' }\r\n';
|
||||
json += '}';
|
||||
|
||||
if (program.template) pkg.dependencies[program.template] = '*';
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
pkg.dependencies['less-middleware'] = '*';
|
||||
break;
|
||||
default:
|
||||
if (program.css) {
|
||||
pkg.dependencies[program.css] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
write(path + '/package.json', JSON.stringify(pkg, null, 2));
|
||||
write(path + '/package.json', json);
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
@@ -352,6 +345,41 @@ function write(path, str) {
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt confirmation with the given `msg`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function confirm(msg, fn) {
|
||||
prompt(msg, function(val){
|
||||
fn(/^ *y(es)?/i.test(val));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt input with the given `msg` and callback `fn`.
|
||||
*
|
||||
* @param {String} msg
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function prompt(msg, fn) {
|
||||
// prompt
|
||||
if (' ' == msg[msg.length - 1]) {
|
||||
process.stdout.write(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
// stdin
|
||||
process.stdin.setEncoding('ascii');
|
||||
process.stdin.once('data', function(data){
|
||||
fn(data);
|
||||
}).resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
|
||||
var http = require('http');
|
||||
|
||||
var times = 50;
|
||||
|
||||
while (times--) {
|
||||
var req = http.request({
|
||||
port: 3000
|
||||
, method: 'POST'
|
||||
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
|
||||
req.on('response', function(res){
|
||||
console.log(res.statusCode);
|
||||
});
|
||||
|
||||
var n = 500000;
|
||||
while (n--) {
|
||||
req.write('foo=bar&bar=baz&');
|
||||
}
|
||||
|
||||
req.write('foo=bar&bar=baz');
|
||||
|
||||
req.end();
|
||||
}
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
+56
-11
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
@@ -180,8 +193,6 @@
|
||||
</a>
|
||||
<div id="wrapper">
|
||||
<div id="container"><ul id="toc">
|
||||
|
||||
</ul><ul id="toc">
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#creating-a server">Creating A Server</a></li>
|
||||
<li><a href="#creating-an https server">Creating An HTTPS Server</a></li>
|
||||
@@ -217,6 +228,7 @@
|
||||
<li><a href="#res.sendfile()">sendfile()</a></li>
|
||||
<li><a href="#res.download()">download()</a></li>
|
||||
<li><a href="#res.send()">send()</a></li>
|
||||
<li><a href="#res.json()">json()</a></li>
|
||||
<li><a href="#res.redirect()">redirect()</a></li>
|
||||
<li><a href="#res.cookie()">cookie()</a></li>
|
||||
<li><a href="#res.clearcookie()">clearCookie()</a></li>
|
||||
@@ -335,6 +347,13 @@ app.configure('production', function(){
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>For similar environments you may also pass several env strings:</p>
|
||||
|
||||
<pre><code>app.configure('stage', 'prod', function(){
|
||||
// config
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>For internal and arbitrary settings Express provides the <em>set(key[, val])</em>, <em>enable(key)</em>, <em>disable(key)</em> methods:</p>
|
||||
|
||||
<pre><code> app.configure(function(){
|
||||
@@ -365,12 +384,14 @@ app.configure('production', function(){
|
||||
<p>Express supports the following settings out of the box:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>home</em> Application base path used for <em>res.redirect()</em> and transparently handling mounted apps.</li>
|
||||
<li><em>basepath</em> Application base path used for <em>res.redirect()</em> and transparently handling mounted apps.</li>
|
||||
<li><em>views</em> Root views directory defaulting to <strong>CWD/views</strong></li>
|
||||
<li><em>view engine</em> Default view engine name for views rendered without extensions</li>
|
||||
<li><em>view options</em> An object specifying global view options</li>
|
||||
<li><em>view cache</em> Enable view caching (enabled in production)</li>
|
||||
<li><em>case sensitive routes</em> Enable case-sensitive routing</li>
|
||||
<li><em>strict routing</em> When enabled trailing slashes are no longer ignored</li>
|
||||
<li><em>jsonp callback</em> Enable <em>res.send()</em> / <em>res.json()</em> transparent jsonp support</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -532,7 +553,7 @@ var app = express.createServer(
|
||||
);
|
||||
</code></pre>
|
||||
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manner.</p>
|
||||
<p>Alternatively we can <em>use()</em> them which is useful when adding middleware within <em>configure()</em> blocks, in a progressive manor.</p>
|
||||
|
||||
<pre><code>app.use(express.logger({ format: ':method :url' }));
|
||||
</code></pre>
|
||||
@@ -658,7 +679,7 @@ app.get('/', all, function(){});
|
||||
|
||||
<h3 id="http-methods">HTTP Methods</h3>
|
||||
|
||||
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manner, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
|
||||
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
|
||||
|
||||
<p> A common example for <em>POST</em> 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.</p>
|
||||
|
||||
@@ -1268,6 +1289,19 @@ it will not be set again.</p>
|
||||
|
||||
<p>Note that this method <em>end()</em>s the response, so you will want to use node’s <em>res.write()</em> for multiple writes or streaming.</p>
|
||||
|
||||
<h3 id="res.json()">res.json(obj[, headers|status[, status]])</h3>
|
||||
|
||||
<p> Send a JSON response with optional <em>headers</em> and <em>status</em>. This method
|
||||
is ideal for JSON-only APIs, however <em>res.send(obj)</em> 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 <em>res.send(string)</em> is text/html.</p>
|
||||
|
||||
<pre><code>res.json(null);
|
||||
res.json({ user: 'tj' });
|
||||
res.json('oh noes!', 500);
|
||||
res.json('I dont have that', 404);
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res.redirect()">res.redirect(url[, status])</h3>
|
||||
|
||||
<p>Redirect to the given <em>url</em> with a default response <em>status</em> of 302.</p>
|
||||
@@ -1281,11 +1315,12 @@ res.redirect('back');
|
||||
|
||||
<p>Express supports “redirect mapping”, which by default provides <em>home</em>, and <em>back</em>.
|
||||
The <em>back</em> map checks the <em>Referrer</em> and <em>Referer</em> headers, while <em>home</em> utilizes
|
||||
the “home” setting and defaults to “/”.</p>
|
||||
the “basepath” setting and defaults to “/”.</p>
|
||||
|
||||
<h3 id="res.cookie()">res.cookie(name, val[, options])</h3>
|
||||
|
||||
<p>Sets the given cookie <em>name</em> to <em>val</em>, with options <em>httpOnly</em>, <em>secure</em>, <em>expires</em> etc.</p>
|
||||
<p>Sets the given cookie <em>name</em> to <em>val</em>, with options <em>httpOnly</em>, <em>secure</em>, <em>expires</em> etc. The <em>path</em> option defaults to the app’s “basepath” setting, which
|
||||
is typically “/”.</p>
|
||||
|
||||
<pre><code>// "Remember me" for 15 minutes
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
@@ -1307,7 +1342,8 @@ app.get('/', function(req, res){
|
||||
|
||||
<h3 id="res.clearcookie()">res.clearCookie(name[, options])</h3>
|
||||
|
||||
<p>Clear cookie <em>name</em> by setting “expires” far in the past.</p>
|
||||
<p>Clear cookie <em>name</em> by setting “expires” far in the past. Much like
|
||||
<em>res.cookie()</em> the <em>path</em> option also defaults to the “basepath” setting.</p>
|
||||
|
||||
<pre><code>res.clearCookie('rememberme');
|
||||
</code></pre>
|
||||
@@ -1324,6 +1360,16 @@ automatically, however otherwise a response of <em>200</em> and <em>text/html</e
|
||||
res.render('index', { layout: false, user: user });
|
||||
</code></pre>
|
||||
|
||||
<p>This <em>options</em> object is also considered an “options” object. For example
|
||||
when you pass the <em>status</em> 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 <em>debug</em>, or <em>compress</em>. Below
|
||||
is an example of how one might render an error page, passing the <em>status</em> for
|
||||
display, as well as it setting <em>res.statusCode</em>.</p>
|
||||
|
||||
<pre><code> res.render('error', { status: 500, message: 'Internal Server Error' });
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res.partial()">res.partial(view[, options])</h3>
|
||||
|
||||
<p>Render <em>view</em> partial with the given <em>options</em>. This method is always available
|
||||
@@ -1451,7 +1497,7 @@ partial('movie', movie)
|
||||
<pre><code> res.local('foo', bar);
|
||||
res.local('bar', baz);
|
||||
|
||||
res.locals({ foo: bar, bar: baz });
|
||||
res.locals({ foo: bar, bar, baz });
|
||||
</code></pre>
|
||||
|
||||
<h3 id="app.set()">app.set(name[, val])</h3>
|
||||
@@ -1596,7 +1642,6 @@ as well as the <em>name()</em> function exposed.</p>
|
||||
<p>Express also provides a few locals by default:</p>
|
||||
|
||||
<pre><code>- `settings` the app's settings object
|
||||
- `filename` the view's filename
|
||||
- `layout(path)` specify the layout from within a view
|
||||
</code></pre>
|
||||
|
||||
@@ -1804,4 +1849,4 @@ Hello World
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
+122
-64
@@ -104,11 +104,11 @@ This is _very_ important, as many caching mechanisms are _only enabled_ when in
|
||||
|
||||
Express supports the following settings out of the box:
|
||||
|
||||
* _home_ Application base path used for _res.redirect()_ and transparently handling mounted apps.
|
||||
* _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)
|
||||
* _charset_ Alter the default charset of "utf-8"
|
||||
* _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
|
||||
@@ -245,7 +245,7 @@ The _app.all()_ method is useful for applying the same logic for all HTTP verbs
|
||||
});
|
||||
|
||||
app.get('*', function(req, res){
|
||||
res.send(404, 'what???');
|
||||
res.send('what???', 404);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -262,7 +262,7 @@ passed to _express.createServer()_ as you would with a regular Connect server. F
|
||||
, express.bodyParser()
|
||||
);
|
||||
|
||||
Alternatively we can _use()_ them which is useful when adding middleware within _configure()_ blocks, in a progressive manner.
|
||||
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' }));
|
||||
|
||||
@@ -379,7 +379,7 @@ There are times when we may want to "skip" passed remaining route middleware, bu
|
||||
|
||||
### 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.
|
||||
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.
|
||||
|
||||
@@ -421,16 +421,65 @@ The reason that these are not always defaults, is simply because these are not r
|
||||
|
||||
### Error Handling
|
||||
|
||||
Error handling middleware are simply middleware with an arity of 4, aka
|
||||
the signature _(err, req, res, next)_. When you _next(err)_ an error,
|
||||
only these middleware are executed and have a chance to respond. For example:
|
||||
|
||||
app.use(app.bodyParser());
|
||||
app.use(app.methodOverride());
|
||||
app.use(app.router);
|
||||
app.use(function(err, req, res, next){
|
||||
res.send(500, 'Server error');
|
||||
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
|
||||
|
||||
@@ -493,11 +542,13 @@ mix and match template engines:
|
||||
|
||||
res.render('another-page.ejs');
|
||||
|
||||
To apply application-level locals, or view engine options may be set using _app.local()_ or _app.locals()_, for example if we don't want layouts for most of our templates we may do:
|
||||
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.local('layout', false);
|
||||
app.set('view options', {
|
||||
layout: false
|
||||
});
|
||||
|
||||
Which can then be overridden within the _res.render()_ call if desired, and is otherwise functionally equivalent to passing directly to `res.render()`:
|
||||
Which can then be overridden within the _res.render()_ call if need be:
|
||||
|
||||
res.render('myview.ejs', { layout: true });
|
||||
|
||||
@@ -513,6 +564,13 @@ 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
|
||||
@@ -589,7 +647,7 @@ Now the _req.session_ and _req.sessionStore_ properties will be accessible to al
|
||||
// we could check req.session.items && req.session.items.length
|
||||
// to print out a message
|
||||
if (req.session.items && req.session.items.length) {
|
||||
req.notify('info', 'You have %s items in your cart', req.session.items.length);
|
||||
req.flash('info', 'You have %s items in your cart', req.session.items.length);
|
||||
}
|
||||
res.render('shopping-cart');
|
||||
});
|
||||
@@ -714,29 +772,27 @@ the _express.bodyParser middleware.
|
||||
req.get('Content-Type', 'boundary');
|
||||
// => "--foo-bar-baz"
|
||||
|
||||
### req.notify(type[, msg])
|
||||
### req.flash(type[, msg])
|
||||
|
||||
Queue flash _msg_ of the given _type_.
|
||||
|
||||
req.notify('info', 'email sent');
|
||||
req.notify('error', 'email delivery failed');
|
||||
req.notify('info', 'email re-sent');
|
||||
req.flash('info', 'email sent');
|
||||
req.flash('error', 'email delivery failed');
|
||||
req.flash('info', 'email re-sent');
|
||||
// => 2
|
||||
|
||||
req.notify('info');
|
||||
req.flash('info');
|
||||
// => ['email sent', 'email re-sent']
|
||||
|
||||
req.notify('info');
|
||||
req.flash('info');
|
||||
// => []
|
||||
|
||||
req.notify();
|
||||
req.flash();
|
||||
// => { error: ['email delivery failed'], info: [] }
|
||||
|
||||
Flash notification message may also utilize formatters, by default only the %s string and %d integer formatters is available:
|
||||
Flash notification message may also utilize formatters, by default only the %s string formatter is available:
|
||||
|
||||
req.notify('info', 'email delivery to <em>%s</em> from <em>%s</em> failed.', toUser, fromUser);
|
||||
|
||||
Argument HTML is escaped, to prevent XSS, however HTML notification format is valid.
|
||||
req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);
|
||||
|
||||
### req.isXMLHttpRequest
|
||||
|
||||
@@ -799,21 +855,6 @@ Sets the _Content-Disposition_ response header to "attachment", with optional _f
|
||||
|
||||
res.attachment('path/to/my/image.png');
|
||||
|
||||
### res.status(code)
|
||||
|
||||
Sets the `res.statusCode` property to `code` and returns for chaining:
|
||||
|
||||
res.status(500).send('Something bad happened');
|
||||
|
||||
is equivalent to:
|
||||
|
||||
res.statusCode = 500;
|
||||
res.send('Something bad happened');
|
||||
|
||||
and:
|
||||
|
||||
res.send(500, 'Something bad happened');
|
||||
|
||||
### res.sendfile(path[, options[, callback]])
|
||||
|
||||
Used by `res.download()` to transfer an arbitrary file.
|
||||
@@ -863,31 +904,36 @@ An optional second callback, _callback2_ may be given to allow you to act on con
|
||||
// connection related error
|
||||
});
|
||||
|
||||
### res.send(body|status[, body])
|
||||
### 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(201, { message: 'User created' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send(404, 'Sorry, cant find that');
|
||||
res.send(404); // "Not Found"
|
||||
res.send(500); // "Internal Server Error"
|
||||
res.send('Sorry, cant find that', 404);
|
||||
res.send('text', { 'Content-Type': 'text/plain' }, 201);
|
||||
res.send(404);
|
||||
|
||||
The _Content-Type_ response header is defaulted appropriately unless previously defined via `res.header()` / `res.contentType()` etc.
|
||||
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|status[, obj])
|
||||
### res.json(obj[, headers|status[, status]])
|
||||
|
||||
Send an explicit JSON response. This method is ideal for JSON-only APIs, while it is much like _res.send(obj)_, send is not ideal for cases when you want to send for example a single string as JSON, since the default for _res.send(string)_ is text/html.
|
||||
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(500, 'oh noes!');
|
||||
res.json(404, 'I dont have that');
|
||||
res.json('oh noes!', 500);
|
||||
res.json('I dont have that', 404);
|
||||
|
||||
### res.redirect(url[, status])
|
||||
|
||||
@@ -901,11 +947,11 @@ Redirect to the given _url_ with a default response _status_ of 302.
|
||||
|
||||
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 "/".
|
||||
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 "home" setting, which
|
||||
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
|
||||
@@ -926,7 +972,7 @@ To parse incoming _Cookie_ headers, use the _cookieParser_ middleware, which pro
|
||||
### 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 "home" setting.
|
||||
_res.cookie()_ the _path_ option also defaults to the "basepath" setting.
|
||||
|
||||
res.clearCookie('rememberme');
|
||||
|
||||
@@ -1163,11 +1209,21 @@ When mounted, _res.redirect()_ will respect the mount-point. For example if a bl
|
||||
|
||||
res.redirect('/posts');
|
||||
|
||||
### app.locals(obj)
|
||||
### app.error(function)
|
||||
|
||||
Registers static view locals.
|
||||
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.locals({
|
||||
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'
|
||||
@@ -1183,14 +1239,16 @@ Express also provides a few locals by default:
|
||||
- `settings` the app's settings object
|
||||
- `layout(path)` specify the layout from within a view
|
||||
|
||||
### app.dynamicLocals(obj)
|
||||
This method is aliased as _app.locals()_.
|
||||
|
||||
Registers dynamic view locals. Dynamic 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, and are unique to that specific request. The _return value_ of this function
|
||||
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.dynamicLocals({
|
||||
app.dynamicHelpers({
|
||||
session: function(req, res){
|
||||
return req.session;
|
||||
}
|
||||
|
||||
+14
-5
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
@@ -233,7 +246,7 @@ app.listen(3000);
|
||||
|
||||
<h2>Third-Party Modules</h2>
|
||||
|
||||
<p>The following modules compliment or extend Express directly:</p>
|
||||
<p>The following modules complement or extend Express directly:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="http://github.com/visionmedia/express-resource">express-resource</a> provides resourceful routing</li>
|
||||
@@ -254,10 +267,6 @@ app.listen(3000);
|
||||
<li><a href="http://groups.google.com/group/express-js">Google Group</a> for discussion</li>
|
||||
<li>Visit the <a href="http://github.com/visionmedia/express/wiki">Wiki</a></li>
|
||||
<li><a href="http://hideyukisaito.com/doc/expressjs/">日本語ドキュメンテーション</a> by <a href="https://github.com/hideyukisaito">hideyukisaito</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eRYu0O">Introduction</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/dU13Fx">View Partials</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/hX4IaH">Route Specific Middleware</a></li>
|
||||
<li>Screencast – <a href="http://bit.ly/eNqmVs">Route Path Placeholder Preconditions</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
+1
-2
@@ -34,7 +34,7 @@ The following are the major contributors of Express (in no specific order).
|
||||
|
||||
## Third-Party Modules
|
||||
|
||||
The following modules compliment or extend Express directly:
|
||||
The following modules complement or extend Express directly:
|
||||
|
||||
* [express-resource](http://github.com/visionmedia/express-resource) provides resourceful routing
|
||||
* [express-messages](http://github.com/visionmedia/express-messages) flash message notification rendering
|
||||
@@ -51,4 +51,3 @@ The following modules compliment or extend Express directly:
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
<title>Express - node web framework</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-25235225-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#tagline {
|
||||
margin-left: 75px;
|
||||
|
||||
+35
-34
@@ -6,49 +6,47 @@
|
||||
var express = require('../../lib/express')
|
||||
, crypto = require('crypto');
|
||||
|
||||
var app = module.exports = express();
|
||||
var app = express.createServer(
|
||||
express.bodyParser()
|
||||
, express.cookieParser()
|
||||
, express.session({ secret: 'keyboard cat' })
|
||||
);
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser('shhhh, very secret'));
|
||||
app.use(express.session());
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
// Session-persisted message middleware
|
||||
// Message helper, ideally we would use req.flash()
|
||||
// however this is more light-weight for an example
|
||||
|
||||
app.locals.use(function(req,res){
|
||||
var err = req.session.error
|
||||
, msg = req.session.success;
|
||||
delete req.session.error;
|
||||
delete req.session.success;
|
||||
res.locals.message = '';
|
||||
if (err) res.locals.message = '<p class="msg error">' + err + '</p>';
|
||||
if (msg) res.locals.message = '<p class="msg success">' + msg + '</p>';
|
||||
})
|
||||
app.dynamicHelpers({
|
||||
message: function(req){
|
||||
var err = req.session.error
|
||||
, msg = req.session.success;
|
||||
delete req.session.error;
|
||||
delete req.session.success;
|
||||
if (err) return '<p class="msg error">' + err + '</p>';
|
||||
if (msg) return '<p class="msg success">' + msg + '</p>';
|
||||
}
|
||||
});
|
||||
|
||||
// Generate a salt for the user to prevent rainbow table attacks
|
||||
// for better security take a look at the bcrypt c++ addon:
|
||||
// https://github.com/ncb000gt/node.bcrypt.js
|
||||
|
||||
var users = {
|
||||
tj: {
|
||||
name: 'tj'
|
||||
name: 'tj'
|
||||
, salt: 'randomly-generated-salt'
|
||||
, pass: hash('foobar', 'randomly-generated-salt')
|
||||
}
|
||||
};
|
||||
|
||||
// Used to generate a hash of the plain-text password + salt
|
||||
function hash(msg, key) {
|
||||
return crypto
|
||||
.createHmac('sha256', key)
|
||||
.update(msg)
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
function hash(msg, key) {
|
||||
return crypto.createHmac('sha256', key).update(msg).digest('hex');
|
||||
}
|
||||
// Authenticate using our plain-object database of doom!
|
||||
|
||||
function authenticate(name, pass, fn) {
|
||||
console.log('authenticating %s:%s', name, pass);
|
||||
var user = users[name];
|
||||
// query the db for the given username
|
||||
if (!user) return fn(new Error('cannot find user'));
|
||||
@@ -69,11 +67,16 @@ function restrict(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
function accessLogger(req, res, next) {
|
||||
console.log('/restricted accessed by %s', req.session.user.name);
|
||||
next();
|
||||
}
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('login');
|
||||
res.redirect('/login');
|
||||
});
|
||||
|
||||
app.get('/restricted', restrict, function(req, res){
|
||||
app.get('/restricted', restrict, accessLogger, function(req, res){
|
||||
res.send('Wahoo! restricted area');
|
||||
});
|
||||
|
||||
@@ -81,7 +84,7 @@ app.get('/logout', function(req, res){
|
||||
// destroy the user's session to log them out
|
||||
// will be re-created next request
|
||||
req.session.destroy(function(){
|
||||
res.redirect('/');
|
||||
res.redirect('home');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,12 +113,10 @@ app.post('/login', function(req, res){
|
||||
req.session.error = 'Authentication failed, please check your '
|
||||
+ ' username and password.'
|
||||
+ ' (use "tj" and "foobar")';
|
||||
res.redirect('login');
|
||||
res.redirect('back');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
@@ -1,6 +1,6 @@
|
||||
<h1>Login</h1>
|
||||
<%- message %>
|
||||
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
|
||||
Try accessing <a href="/restricted">/restricted</a>.
|
||||
<form method="post" action="/login">
|
||||
<p>
|
||||
<label>Username:</label>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, messages = require('express-messages');
|
||||
|
||||
var app = module.exports = express.createServer();
|
||||
|
||||
// Config
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// mount hook
|
||||
|
||||
app.mounted(function(other){
|
||||
console.log('ive been mounted!');
|
||||
});
|
||||
|
||||
// Flash message helper provided by express-messages
|
||||
// $ npm install express-messages
|
||||
|
||||
app.dynamicHelpers({
|
||||
messages: messages
|
||||
, base: function(){
|
||||
// return the app's mount-point
|
||||
// so that urls can adjust. For example
|
||||
// if you run this example /post/add works
|
||||
// however if you run the mounting example
|
||||
// it adjusts to /blog/post/add
|
||||
return '/' == app.route ? '' : app.route;
|
||||
}
|
||||
});
|
||||
|
||||
// Middleware
|
||||
|
||||
app.configure(function(){
|
||||
app.use(express.logger('\x1b[33m:method\x1b[0m \x1b[32m:url\x1b[0m :response-time'));
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
require('./routes/site')(app);
|
||||
require('./routes/post')(app);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
// config
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// middleware
|
||||
|
||||
app.configure('development',function(){
|
||||
app.use(express.logger('dev'));
|
||||
})
|
||||
|
||||
app.configure(function(){
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.cookieParser('keyboard cat'));
|
||||
app.use(express.session());
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
|
||||
});
|
||||
|
||||
// Locals
|
||||
|
||||
app.locals.use(function(req, res){
|
||||
// expose "error" and "message" to all
|
||||
// views that are rendered.
|
||||
res.locals.error = req.session.error || '';
|
||||
res.locals.message = req.session.message || '';
|
||||
// remove them so they're not displayed on subsequent renders
|
||||
delete req.session.error;
|
||||
delete req.session.message;
|
||||
});
|
||||
|
||||
// Routes
|
||||
|
||||
require('./routes/site')(app);
|
||||
require('./routes/post')(app);
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -17,11 +17,11 @@ Post.prototype.save = function(fn){
|
||||
};
|
||||
|
||||
Post.prototype.validate = function(fn){
|
||||
if (!this.title) return fn(new Error('title required'));
|
||||
if (!this.body) return fn(new Error('body required'));
|
||||
if (!this.title) return fn(new Error('_title_ required'));
|
||||
if (!this.body) return fn(new Error('_body_ required'));
|
||||
if (this.body.length < 10) {
|
||||
return fn(new Error(
|
||||
'body should be at least 10 characters long, was only ' + this.title.length));
|
||||
'_body_ should be at least **10** characters long, was only _' + this.title.length + '_'));
|
||||
}
|
||||
fn();
|
||||
};
|
||||
|
||||
@@ -41,16 +41,18 @@ a.edit {
|
||||
.date {
|
||||
font-size: 11px;
|
||||
}
|
||||
p.error,
|
||||
p.message {
|
||||
#messages ul {
|
||||
padding: 10px;
|
||||
border: 1px solid;
|
||||
}
|
||||
p.error {
|
||||
background: #FDEAE7;
|
||||
color: #E4250C;
|
||||
#messages ul li {
|
||||
list-style: none;
|
||||
}
|
||||
p.message {
|
||||
#messages ul.info {
|
||||
color: #2EBBE6;
|
||||
background: #F7FBFD;
|
||||
}
|
||||
#messages ul.error {
|
||||
color: #E4250C;
|
||||
background: #FDEAE7;
|
||||
}
|
||||
@@ -42,17 +42,17 @@ module.exports = function(app){
|
||||
*/
|
||||
|
||||
app.post('/post', function(req, res){
|
||||
var data = req.body.post || {}
|
||||
var data = req.body.post
|
||||
, post = new Post(data.title, data.body);
|
||||
|
||||
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.session.error = err.message;
|
||||
req.flash('error', err.message);
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
post.save(function(err){
|
||||
req.session.message = 'Successfully created the post.';
|
||||
req.flash('info', 'Successfully created post _%s_', post.title);
|
||||
res.redirect('/post/' + post.id);
|
||||
});
|
||||
});
|
||||
@@ -82,13 +82,12 @@ module.exports = function(app){
|
||||
var post = req.post;
|
||||
post.validate(function(err){
|
||||
if (err) {
|
||||
req.session.error = err.message;
|
||||
req.flash('error', err.message);
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
post.update(req.body.post, function(err){
|
||||
if (err) return next(err);
|
||||
req.session.message = 'Successfully updated post';
|
||||
req.flash('info', 'Successfully updated post');
|
||||
res.redirect('back');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
extends layout
|
||||
h1 Blog
|
||||
|
||||
block content
|
||||
h1 Blog
|
||||
!= messages()
|
||||
|
||||
if count
|
||||
p Display all #{count} post(s)
|
||||
#posts
|
||||
each post in posts
|
||||
include post/index
|
||||
else
|
||||
p
|
||||
| It looks like you have no posts!
|
||||
p
|
||||
| Click
|
||||
a(href='/post/add') here
|
||||
| to create a post. Login
|
||||
| as
|
||||
em "admin"
|
||||
| and
|
||||
em "express"
|
||||
| .
|
||||
- if (count)
|
||||
p Display all #{count} post(s)
|
||||
#posts!= partial('post', posts)
|
||||
- else
|
||||
p
|
||||
| It looks like you have no posts!
|
||||
p
|
||||
| Click
|
||||
a(href=base + '/post/add') here
|
||||
| to create a post. Login
|
||||
| as
|
||||
em "admin"
|
||||
| and
|
||||
em "express"
|
||||
| .
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
html
|
||||
head
|
||||
title Blog
|
||||
link(rel='stylesheet', href='/style.css')
|
||||
link(rel='stylesheet', href=base + '/style.css')
|
||||
body
|
||||
#container
|
||||
block content
|
||||
#container!= body
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
if error
|
||||
p.error= error
|
||||
|
||||
if message
|
||||
p.message= message
|
||||
@@ -1,22 +1,20 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
if post.title
|
||||
h1 Editing #{post.title}
|
||||
else
|
||||
h1 New Post
|
||||
- if (post.title)
|
||||
h1 Editing #{post.title}
|
||||
- else
|
||||
h1 New Post
|
||||
|
||||
include ../messages
|
||||
!= messages()
|
||||
|
||||
form#post(action='/post' + (post.title ? '/' + post.id : ''), method='post')
|
||||
if post.title
|
||||
input(type='hidden', name='_method', value='put')
|
||||
p
|
||||
label(for='post[title]') Title:
|
||||
input(type='text', name='post[title]', value=post.title)
|
||||
p
|
||||
label(for='post[body]') Body:
|
||||
textarea(name='post[body]')= post.body || ''
|
||||
p
|
||||
input(type='submit', value=post.title ? 'Update' : 'Create')
|
||||
|
||||
form#post(action=base + '/post' + (post.title ? '/' + post.id : ''), method='post')
|
||||
- if (post.title)
|
||||
input(type='hidden', name='_method', value='put')
|
||||
p
|
||||
label(for='post[title]') Title:
|
||||
input(type='text', name='post[title]', value=post.title)
|
||||
p
|
||||
label(for='post[body]') Body:
|
||||
textarea(name='post[body]')= post.body || ''
|
||||
p
|
||||
input(type='submit', value=post.title ? 'Update' : 'Create')
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
.post
|
||||
// title
|
||||
h2
|
||||
= post.title
|
||||
a.edit(href='/post/' + post.id + '/edit') Edit
|
||||
|
||||
include ../messages
|
||||
|
||||
// dates
|
||||
p.date.created Created at #{post.createdAt}
|
||||
if post.updatedAt
|
||||
p.date.updated Updated at #{post.updatedAt}
|
||||
|
||||
// body
|
||||
pre.body= post.body
|
||||
.post
|
||||
// title
|
||||
h2
|
||||
= post.title
|
||||
a.edit(href=base + '/post/' + post.id + '/edit') Edit
|
||||
|
||||
// flash messages
|
||||
!= messages()
|
||||
|
||||
// dates
|
||||
p.date.created Created at #{post.createdAt}
|
||||
- if (post.updatedAt)
|
||||
p.date.updated Updated at #{post.updatedAt}
|
||||
|
||||
// body
|
||||
pre.body= post.body
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
var users = [
|
||||
{ name: 'tobi' }
|
||||
, { name: 'loki' }
|
||||
, { name: 'jane' }
|
||||
];
|
||||
|
||||
function provides(type) {
|
||||
return function(req, res, next){
|
||||
if (req.accepts(type)) return next();
|
||||
next('route');
|
||||
}
|
||||
}
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: application/json"
|
||||
|
||||
app.get('/users', provides('json'), function(req, res){
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: text/html"
|
||||
|
||||
app.get('/users', provides('html'), function(req, res){
|
||||
res.send('<ul>' + users.map(function(user){
|
||||
return '<li>' + user.name + '</li>';
|
||||
}).join('\n') + '</ul>');
|
||||
});
|
||||
|
||||
// curl http://localhost:3000/users -H "Accept: text/plain"
|
||||
|
||||
app.get('/users', function(req, res, next){
|
||||
res.contentType('txt');
|
||||
res.send(users.map(function(user){
|
||||
return user.name;
|
||||
}).join(', '));
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
|
||||
var users = [];
|
||||
|
||||
users.push({ name: 'Tobi' });
|
||||
users.push({ name: 'Loki' });
|
||||
users.push({ name: 'Jane' });
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.format({
|
||||
html: function(){
|
||||
res.send('<ul>' + users.map(function(user){
|
||||
return '<li>' + user.name + '</li>';
|
||||
}).join('') + '</ul>');
|
||||
},
|
||||
|
||||
text: function(){
|
||||
res.send(users.map(function(user){
|
||||
return ' - ' + user.name + '\n';
|
||||
}).join(''));
|
||||
},
|
||||
|
||||
json: function(){
|
||||
res.json(users);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// pass a secret to cookieParser() for signed cookies
|
||||
app.use(express.cookieParser('manny is cool'));
|
||||
|
||||
// add req.session cookie support
|
||||
app.use(express.cookieSessions());
|
||||
|
||||
// do something with the session
|
||||
app.use(count);
|
||||
|
||||
// custom middleware
|
||||
function count(req, res) {
|
||||
req.session.count = req.session.count || 0;
|
||||
var n = req.session.count++;
|
||||
res.send('viewed ' + n + ' times\n');
|
||||
}
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
+14
-23
@@ -3,29 +3,22 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer(
|
||||
// Place default Connect favicon above logger so it is not in
|
||||
// the logging output
|
||||
express.favicon(),
|
||||
|
||||
// add favicon() before logger() so
|
||||
// GET /favicon.ico requests are not
|
||||
// logged, because this middleware
|
||||
// reponds to /favicon.ico and does not
|
||||
// call next()
|
||||
app.use(express.favicon());
|
||||
// Custom logger format
|
||||
express.logger({ format: '\x1b[36m:method\x1b[0m \x1b[90m:url\x1b[0m :response-time' }),
|
||||
|
||||
// custom log format
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger(':method :url'));
|
||||
// Provides req.cookies
|
||||
express.cookieParser(),
|
||||
|
||||
// parses request cookies, populating
|
||||
// req.cookies and req.signedCookies
|
||||
// when the secret is passed, used
|
||||
// for signing the cookies.
|
||||
app.use(express.cookieParser('my secret here'));
|
||||
|
||||
// parses json, x-www-form-urlencoded, and multipart/form-data
|
||||
app.use(express.bodyParser());
|
||||
// Parses x-www-form-urlencoded request bodies (and json)
|
||||
express.bodyParser()
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
if (req.cookies.remember) {
|
||||
@@ -48,7 +41,5 @@ app.post('/', function(req, res){
|
||||
res.redirect('back');
|
||||
});
|
||||
|
||||
if (!module.parent){
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
+24
-17
@@ -3,8 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<ul>'
|
||||
@@ -18,27 +19,33 @@ app.get('/', function(req, res){
|
||||
app.get('/files/:file(*)', function(req, res, next){
|
||||
var file = req.params.file
|
||||
, path = __dirname + '/files/' + file;
|
||||
// either res.download(path) and let
|
||||
// express handle failures, or provide
|
||||
// a callback as shown below
|
||||
res.download(path, function(err){
|
||||
// if an error occurs in this callback
|
||||
// the file most likely does not exist,
|
||||
// and it's safe to respond or next(err)
|
||||
if (err) return next(err);
|
||||
|
||||
res.download(path);
|
||||
// the file has been transferred, do not respond
|
||||
// from here, though you may use this callback
|
||||
// for stats etc.
|
||||
console.log('transferred %s', path);
|
||||
}, function(err){
|
||||
// this second optional callback is used when
|
||||
// an error occurs during transmission
|
||||
});
|
||||
});
|
||||
|
||||
// error handling middleware. Because it's
|
||||
// below our routes, you will be able to
|
||||
// "intercept" errors, otherwise Connect
|
||||
// will respond with 500 "Internal Server Error".
|
||||
app.use(function(err, req, res, next){
|
||||
// special-case 404s,
|
||||
// remember you could
|
||||
// render a 404 template here
|
||||
if (404 == err.status) {
|
||||
res.statusCode = 404;
|
||||
app.error(function(err, req, res, next){
|
||||
if ('ENOENT' == err.code) {
|
||||
res.send('Cant find that file, sorry!');
|
||||
} else {
|
||||
// Not a 404
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Register ejs as .html
|
||||
|
||||
app.register('.html', require('ejs'));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' }
|
||||
, { name: 'ciaran', email: 'ciaranj@gmail.com' }
|
||||
, { name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,46 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// Register ejs as .html. If we did
|
||||
// not call this, we would need to
|
||||
// name our views foo.ejs instead
|
||||
// of foo.html. The __express method
|
||||
// is simply a function that engines
|
||||
// use to hook into the Express view
|
||||
// system by default, so if we want
|
||||
// to change "foo.ejs" to "foo.html"
|
||||
// we simply pass _any_ function, in this
|
||||
// case `ejs.__express`.
|
||||
|
||||
app.engine('.html', require('ejs').__express);
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Without this you would need to
|
||||
// supply the extension to res.render()
|
||||
// ex: res.render('users.html').
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tobi', email: 'tobi@learnboost.com' }
|
||||
, { name: 'loki', email: 'loki@learnboost.com' }
|
||||
, { name: 'jane', email: 'jane@learnboost.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +0,0 @@
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<% users.forEach(function(user){ %>
|
||||
<li><%= user.name %> <%= user.email %></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
@@ -0,0 +1,3 @@
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -1,25 +1,27 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, silent = 'test' == process.env.NODE_ENV;
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// Serve default connect favicon
|
||||
app.use(express.favicon());
|
||||
|
||||
silent || app.use(express.logger('dev'));
|
||||
// Logger is placed below favicon, so favicon.ico
|
||||
// requests will not be logged
|
||||
app.use(express.logger('":method :url" :status'));
|
||||
|
||||
// "app.router" positions our routes
|
||||
// above the middleware defined below,
|
||||
// this means that Express will attempt
|
||||
// to match & call routes _before_ continuing
|
||||
// on, at which point we assume it's a 404 because
|
||||
// no route has handled the request.
|
||||
// specifically above the middleware
|
||||
// assigned below
|
||||
|
||||
app.use(app.router);
|
||||
|
||||
@@ -27,26 +29,11 @@ app.use(app.router);
|
||||
// middleware use()d, we assume 404, as nothing else
|
||||
// responded.
|
||||
|
||||
// $ curl http://localhost:3000/notfound
|
||||
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
|
||||
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
|
||||
|
||||
app.use(function(req, res, next){
|
||||
// respond with html page
|
||||
if (req.accepts('html')) {
|
||||
res.status(404);
|
||||
res.render('404', { url: req.url });
|
||||
return;
|
||||
}
|
||||
|
||||
// respond with json
|
||||
if (req.accepts('json')) {
|
||||
res.send({ error: 'Not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
// default to plain-text. send()
|
||||
res.type('txt').send('Not found');
|
||||
// the status option, or res.statusCode = 404
|
||||
// are equivalent, however with the option we
|
||||
// get the "status" local available as well
|
||||
res.render('404', { status: 404, url: req.url });
|
||||
});
|
||||
|
||||
// error-handling middleware, take the same form
|
||||
@@ -61,12 +48,15 @@ app.use(function(req, res, next){
|
||||
// would remain being executed, however here
|
||||
// we simply respond with an error page.
|
||||
|
||||
|
||||
app.use(function(err, req, res, next){
|
||||
// we may use properties of the error object
|
||||
// here and next(err) appropriately, or if
|
||||
// we possibly recovered from the error, simply next().
|
||||
res.status(err.status || 500);
|
||||
res.render('500', { error: err });
|
||||
res.render('500', {
|
||||
status: err.status || 500
|
||||
, error: err
|
||||
});
|
||||
});
|
||||
|
||||
// Routes
|
||||
@@ -89,7 +79,5 @@ app.get('/500', function(req, res, next){
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,5 +1 @@
|
||||
|
||||
extends error
|
||||
|
||||
block content
|
||||
h2 Cannot find #{url}
|
||||
h2 Cannot find #{url}
|
||||
@@ -1,10 +1,2 @@
|
||||
|
||||
// note that we extend a different
|
||||
// layout with jade for 4xx & 5xx
|
||||
// responses
|
||||
|
||||
extends error
|
||||
|
||||
block content
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
@@ -1,6 +0,0 @@
|
||||
html
|
||||
head
|
||||
title Error
|
||||
body
|
||||
h1 An error occurred!
|
||||
block content
|
||||
@@ -1,15 +1,11 @@
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
li
|
||||
| visit
|
||||
a(href='/403') 403
|
||||
h2 Pages Example
|
||||
ul
|
||||
li
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
li
|
||||
| visit
|
||||
a(href='/403') 403
|
||||
@@ -3,4 +3,4 @@ html
|
||||
title Custom Pages Example
|
||||
body
|
||||
h1 My Site
|
||||
block content
|
||||
!= body
|
||||
+10
-33
@@ -3,33 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
var express = require('../../lib/express');
|
||||
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger('dev'));
|
||||
app.use(app.router);
|
||||
|
||||
// the error handler is strategically
|
||||
// placed *below* the app.router; if it
|
||||
// were above it would not receive errors
|
||||
// from app.get() etc
|
||||
app.use(error);
|
||||
|
||||
// error handling middleware have an arity of 4
|
||||
// instead of the typical (req, res, next),
|
||||
// otherwise they behave exactly like regular
|
||||
// middleware, you may have several of them,
|
||||
// in different orders etc.
|
||||
|
||||
function error(err, req, res, next) {
|
||||
// log it
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
console.error(err.stack);
|
||||
|
||||
// respond with 500 "Internal Server Error".
|
||||
res.send(500);
|
||||
}
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Caught and passed down to the errorHandler middleware
|
||||
@@ -38,12 +14,13 @@ app.get('/', function(req, res){
|
||||
|
||||
app.get('/next', function(req, res, next){
|
||||
// We can also pass exceptions to next()
|
||||
process.nextTick(function(){
|
||||
next(new Error('oh no!'));
|
||||
});
|
||||
next(new Error('oh no!'))
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
// The errorHandler middleware in this case will dump exceptions to stderr
|
||||
// as well as show the stack trace in responses, currently handles text/plain,
|
||||
// text/html, and application/json responses to aid in development
|
||||
app.use('/', express.errorHandler({ dump: true, stack: true }));
|
||||
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Register ejs as .html
|
||||
|
||||
app.register('.html', require('ejs'));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tj', email: 'tj@sencha.com' }
|
||||
, { name: 'ciaran', email: 'ciaranj@gmail.com' }
|
||||
, { name: 'aaron', email: 'aaron.heckmann+github@gmail.com' }
|
||||
];
|
||||
|
||||
// dynamic helpers are simply functions that are invoked
|
||||
// per request (once), passed both the request and response
|
||||
// objects. These can be used for request-specific
|
||||
// details within a view, such telling the layout which
|
||||
// scripts to include.
|
||||
app.dynamicHelpers({
|
||||
// by simply returning an object here
|
||||
// we can set it's properties such as "page.title"
|
||||
// within a view, and it remains specific to that request,
|
||||
// so it would be valid to do:
|
||||
// page.title = user.name + "'s account"
|
||||
page: function() {
|
||||
return {};
|
||||
},
|
||||
|
||||
// the scripts array here is assigned once,
|
||||
// so by returning a closure, we can use script(path)
|
||||
// in a template, instead of something like
|
||||
// scripts.push(path).
|
||||
script: function(req){
|
||||
req._scripts = [];
|
||||
return function(path){
|
||||
req._scripts.push(path);
|
||||
}
|
||||
},
|
||||
|
||||
// to expose our scripts array for iteration within
|
||||
// our views (typically the layout), we simply return it
|
||||
// here, and since composite types are mutable, it will
|
||||
// contain all of the paths pushed with the helper above.
|
||||
scripts: function(req){
|
||||
return req._scripts;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%- page.title %></title>
|
||||
<% for (var i in scripts) { %>
|
||||
<script src="<%= scripts[i] %>"></script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<% page.title = 'Users' %>
|
||||
<% script('/javascripts/jquery.js') %>
|
||||
<% script('/javascripts/users.js') %>
|
||||
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<%- partial('user', users) %>
|
||||
</ul>
|
||||
@@ -0,0 +1 @@
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
// App with session support
|
||||
|
||||
var app = express.createServer(
|
||||
express.cookieParser()
|
||||
, express.session({ secret: 'keyboard cat' })
|
||||
);
|
||||
|
||||
// View settings
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
app.dynamicHelpers({
|
||||
// express-messages is a dynamicHelper that
|
||||
// renders the flash messages to HTML for you
|
||||
// $ npm install express-messages
|
||||
messages: require('express-messages')
|
||||
});
|
||||
|
||||
app.dynamicHelpers({
|
||||
// Another dynamic helper example. Since dynamic
|
||||
// helpers resolve at view rendering time, we can
|
||||
// "inject" the "page" local variable per request
|
||||
// providing us with the request url.
|
||||
page: function(req, res){
|
||||
return req.url;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// Not very realistic notifications but illustrates usage
|
||||
req.flash('info', 'email queued');
|
||||
req.flash('info', 'email sent');
|
||||
req.flash('error', 'delivery failed');
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,3 @@
|
||||
<h1>Flash Message Example</h1>
|
||||
<p>on page <%- page %></p>
|
||||
<%- messages() %>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +1,14 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = module.exports = express();
|
||||
var app = express.createServer();
|
||||
|
||||
// Here we use the bodyDecoder middleware
|
||||
// to parse urlencoded request bodies
|
||||
@@ -73,7 +77,5 @@ app.put('/', function(req, res){
|
||||
res.redirect('/?name=' + req.body.name);
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -3,9 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = module.exports = express();
|
||||
var app = express.createServer();
|
||||
|
||||
// Fake items
|
||||
|
||||
@@ -45,7 +45,8 @@ app.get('/item/:id.:format?', function(req, res, next){
|
||||
+ '<items>'
|
||||
+ '<item>' + item.name + '</item>'
|
||||
+ '</items>';
|
||||
res.type('xml').send(xml);
|
||||
res.contentType('.xml');
|
||||
res.send(xml);
|
||||
break;
|
||||
case 'html':
|
||||
default:
|
||||
@@ -61,9 +62,7 @@ app.get('/item/:id.:format?', function(req, res, next){
|
||||
|
||||
// Middleware
|
||||
|
||||
app.use(express.errorHandler());
|
||||
app.use(express.errorHandler({ showStack: true }));
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -6,7 +6,7 @@
|
||||
var express = require('../../lib/express')
|
||||
, http = require('http');
|
||||
|
||||
var app = express();
|
||||
var app = express.createServer();
|
||||
|
||||
// Expose our views
|
||||
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
each user in users
|
||||
.user
|
||||
h2= user.name
|
||||
p.summary
|
||||
| <a href="http://github.com/#{user.name}">#{user.name}</a> has
|
||||
| <strong>#{user.repos.length}</strong> repositories
|
||||
| with a total of <strong>#{user.totalWatchers}</strong> watchers.
|
||||
table#repos
|
||||
for repo in user.repos
|
||||
include repo
|
||||
- each user in users
|
||||
.user
|
||||
h2= user.name
|
||||
p.summary
|
||||
| <a href="http://github.com/#{user.name}">#{user.name}</a> has
|
||||
| <strong>#{user.repos.length}</strong> repositories
|
||||
| with a total of <strong>#{user.totalWatchers}</strong> watchers.
|
||||
table#repos!= partial('repo', user.repos)
|
||||
@@ -4,5 +4,4 @@ html
|
||||
title Github Example
|
||||
link(rel="stylesheet", href="/style.css")
|
||||
body
|
||||
#container
|
||||
block content
|
||||
#container!= body
|
||||
@@ -3,13 +3,12 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express();
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
|
||||
+8
-19
@@ -13,13 +13,17 @@ var pub = __dirname + '/public';
|
||||
// and then serve with connect's staticProvider
|
||||
|
||||
var app = express.createServer();
|
||||
app.use(express.logger('dev'));
|
||||
app.use(express.compiler({ src: pub, enable: ['sass'] }));
|
||||
app.use(app.router);
|
||||
app.use(express.static(pub));
|
||||
app.use(express.errorHandler({ dump: true, stack: true }));
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
// we're using jade's template inheritance, so we dont need
|
||||
// the express layout concept
|
||||
app.set('view options', { layout: false });
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Set our default template engine to "jade"
|
||||
@@ -34,30 +38,15 @@ function User(name, email) {
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
new User('tj', 'tj@vision-media.ca')
|
||||
, new User('ciaran', 'ciaranj@gmail.com')
|
||||
, new User('aaron', 'aaron.heckmann+github@gmail.com')
|
||||
new User('Tobi', 'tobi@learnboost.com')
|
||||
, new User('Loki', 'loki@learnboost.com')
|
||||
, new User('Jane', 'jane@learnboost.com')
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
app.get('/users/callback', function(req, res){
|
||||
// a callback is also accepted
|
||||
res.partial('users/user', users, function(err, html){
|
||||
if (err) throw err;
|
||||
res.send(html);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res){
|
||||
// we can use res.partial() as if
|
||||
// we were in a view, utilizing the same api
|
||||
// to render a fragment
|
||||
res.partial('users/user', users);
|
||||
});
|
||||
|
||||
app.get('/users/list', function(req, res){
|
||||
// use "object" to utilize the name deduced from
|
||||
// the view filename. The examples below are equivalent
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
head
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
@@ -1,4 +1,8 @@
|
||||
!!!
|
||||
doctype 5
|
||||
html
|
||||
include header
|
||||
body!= body
|
||||
head
|
||||
block title
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
body
|
||||
block content
|
||||
@@ -1,3 +1,12 @@
|
||||
- if (users.length)
|
||||
h1 Users
|
||||
#users!= partial('user', users)
|
||||
|
||||
extends ../layout
|
||||
|
||||
block title
|
||||
title Users
|
||||
|
||||
block content
|
||||
if users.length
|
||||
h1 Users
|
||||
#users
|
||||
for user in users
|
||||
include ./user
|
||||
@@ -1,3 +1,4 @@
|
||||
ul#users
|
||||
- each user in list
|
||||
li!= partial('user', user)
|
||||
for user in list
|
||||
li
|
||||
include ./user
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
app = express.createServer();
|
||||
|
||||
// load the config for this environment (NODE_ENV)
|
||||
|
||||
var config = require('./config')[app.settings.env];
|
||||
|
||||
// apply settings
|
||||
|
||||
for (var key in config) app.set(key, config[key]);
|
||||
|
||||
// apply middleware
|
||||
|
||||
config.middleware.forEach(app.use.bind(app));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', { layout: false });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
// ok so it's not JSON, but close enough :)
|
||||
|
||||
var express = require('../../');
|
||||
|
||||
exports.development = {
|
||||
'view engine': 'jade'
|
||||
, 'views': __dirname + '/views'
|
||||
, 'title': 'My Site'
|
||||
, 'middleware': [
|
||||
express.logger('dev')
|
||||
, app.router
|
||||
, express.static(__dirname + '/public')
|
||||
]
|
||||
};
|
||||
|
||||
exports.production = {
|
||||
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
html
|
||||
body
|
||||
h1 #{settings.title}
|
||||
p Simple example
|
||||
@@ -3,49 +3,29 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, url = require('url');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// map .html to ejs module
|
||||
app.register('html', require('ejs'));
|
||||
app.set('view engine', 'html');
|
||||
|
||||
// set default layout, usually "layout"
|
||||
app.locals.layout = 'layouts/default';
|
||||
app.set('view options', { layout: 'layouts/default' });
|
||||
|
||||
app.use(function(req, res, next){
|
||||
// expose the current path as a view local
|
||||
res.locals.path = url.parse(req.url).pathname;
|
||||
|
||||
// assign content str for section
|
||||
res.locals.contentFor = function(section, str){
|
||||
res.locals[section] = str;
|
||||
};
|
||||
|
||||
next();
|
||||
});
|
||||
// Set our default template engine to "ejs"
|
||||
// which prevents the need for extensions
|
||||
// (although you can still mix and match)
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('page');
|
||||
res.render('pages/default');
|
||||
});
|
||||
|
||||
app.get('/alternate', function(req, res){
|
||||
res.render('page', { layout: 'layouts/alternate' });
|
||||
});
|
||||
|
||||
app.get('/alternate2', function(req, res){
|
||||
res.render('page2');
|
||||
});
|
||||
|
||||
app.get('/defined-in-view', function(req, res){
|
||||
// note that we do not explicitly
|
||||
// state the layout here, the view does,
|
||||
// although we could do it here as well.
|
||||
res.render('pages');
|
||||
res.render('pages/alternate');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<p>Moar sidebar here</p>
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Alternate Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,26 +0,0 @@
|
||||
<html>
|
||||
<title>Alternate</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px "helvetica neue", helvetica, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
#sidebar {
|
||||
float: left;
|
||||
width: 150px;
|
||||
}
|
||||
#content {
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>Alternate Layout</h1>
|
||||
<div id="sidebar">
|
||||
<%- sidebar %>
|
||||
</div>
|
||||
<div id="content">
|
||||
<%- body %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>Default Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,16 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Default</title>
|
||||
<style>
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px "helvetica neue", helvetica, sans-serif;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Default Layout</h1>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
<h1>Page</h1>
|
||||
<% if (path == '/alternate') { %>
|
||||
<% contentFor('sidebar', partial('alternate-sidebar')) %>
|
||||
<p>Click <a href="/">here</a> to view the default layout.</p>
|
||||
<p>Click <a href="/alternate2">here</a> to view another alternate page.</p>
|
||||
<% } else { %>
|
||||
<p>Click <a href="/alternate">here</a> to view the alternate layout.</p>
|
||||
<% } %>
|
||||
@@ -1,4 +0,0 @@
|
||||
<% layout('layouts/alternate') %>
|
||||
<% contentFor('sidebar', '<p>Another sidebar here</p>') %>
|
||||
<h1>Page</h1>
|
||||
<p>Click <a href="/">here</a> to view the default layout.</p>
|
||||
@@ -0,0 +1,2 @@
|
||||
<% layout('layouts/alternate') %>
|
||||
<h1>Page</h1>
|
||||
@@ -0,0 +1 @@
|
||||
<h1>Page</h1>
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, md = require('node-markdown').Markdown;
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// register .md so that markdown may comply
|
||||
// with the express view system by implementing
|
||||
// a .compile() method
|
||||
|
||||
app.register('.md', {
|
||||
compile: function(str, options){
|
||||
var html = md(str);
|
||||
return function(locals){
|
||||
return html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return locals[name];
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'md');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', { layout: false, title: 'Markdown Example' });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, fs = require('fs')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// register .md as an engine in express view system
|
||||
|
||||
app.engine('md', function(path, options, fn){
|
||||
fs.readFile(path, 'utf8', function(err, str){
|
||||
if (err) return fn(err);
|
||||
try {
|
||||
var html = md(str);
|
||||
html = html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return options[name] || '';
|
||||
})
|
||||
fn(null, html);
|
||||
} catch(err) {
|
||||
fn(err);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// make it the default so we dont need .md
|
||||
app.set('view engine', 'md');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index', { title: 'Markdown Example' });
|
||||
})
|
||||
|
||||
app.get('/fail', function(req, res){
|
||||
res.render('missing', { title: 'Markdown Example' });
|
||||
})
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, blog = require('../blog/app');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
|
||||
// mount the blog. the blog app is written using the "base"
|
||||
// local variable, allowing it's urls to adjust to wherever
|
||||
// we wish to mount it.
|
||||
app.use('/blog', blog);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Visit <a href="/blog">/blog</a>');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Server listening on port 3000');
|
||||
+31
-19
@@ -3,34 +3,46 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, format = require('util').format;
|
||||
var express = require('../../lib/express')
|
||||
, form = require('connect-form');
|
||||
|
||||
var app = module.exports = express()
|
||||
|
||||
// bodyParser in connect 2.x uses node-formidable to parse
|
||||
// the multipart form data.
|
||||
app.use(express.bodyParser())
|
||||
var app = express.createServer(
|
||||
// connect-form (http://github.com/visionmedia/connect-form)
|
||||
// middleware uses the formidable middleware to parse urlencoded
|
||||
// and multipart form data
|
||||
form({ keepExtensions: true })
|
||||
);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<form method="post" enctype="multipart/form-data">'
|
||||
+ '<p>Title: <input type="text" name="title" /></p>'
|
||||
+ '<p>Image: <input type="file" name="image" /></p>'
|
||||
+ '<p><input type="submit" value="Upload" /></p>'
|
||||
+ '</form>');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res, next){
|
||||
// the uploaded file can be found as `req.files.image` and the
|
||||
// title field as `req.body.title`
|
||||
res.send(format('\nuploaded %s (%d Kb) to %s as %s'
|
||||
, req.files.image.name
|
||||
, req.files.image.size / 1024 | 0
|
||||
, req.files.image.path
|
||||
, req.body.title));
|
||||
|
||||
// connect-form adds the req.form object
|
||||
// we can (optionally) define onComplete, passing
|
||||
// the exception (if any) fields parsed, and files parsed
|
||||
req.form.complete(function(err, fields, files){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
console.log('\nuploaded %s to %s'
|
||||
, files.image.filename
|
||||
, files.image.path);
|
||||
res.redirect('back');
|
||||
}
|
||||
});
|
||||
|
||||
// We can add listeners for several form
|
||||
// events such as "progress"
|
||||
req.form.on('progress', function(bytesReceived, bytesExpected){
|
||||
var percent = (bytesReceived / bytesExpected * 100) | 0;
|
||||
process.stdout.write('Uploading: %' + percent + '\r');
|
||||
});
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -23,7 +23,8 @@ function bootApplication(app) {
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// Example 500 page
|
||||
app.use(function(err, req, res, next){
|
||||
app.error(function(err, req, res){
|
||||
console.dir(err)
|
||||
res.render('500');
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express();
|
||||
var express = require('../../lib/express')
|
||||
, app = express.createServer();
|
||||
|
||||
// Faux database
|
||||
|
||||
@@ -18,14 +18,7 @@ var users = [
|
||||
|
||||
// Convert :to and :from to integers
|
||||
|
||||
app.param(['to', 'from'], function(req, res, next, num, name){
|
||||
req.params[name] = num = parseInt(num, 10);
|
||||
if( isNaN(num) ){
|
||||
next(new Error('failed to parseInt '+num));
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
app.param(['to', 'from'], function(n){ return parseInt(n, 10); });
|
||||
|
||||
// Load user by id
|
||||
|
||||
@@ -64,7 +57,5 @@ app.get('/users/:from-:to', function(req, res, next){
|
||||
res.send('users ' + names.slice(from, to).join(', '));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express application listening on port 3000');
|
||||
@@ -3,9 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = module.exports = express();
|
||||
var app = express.createServer();
|
||||
|
||||
// Ad-hoc example resource method
|
||||
|
||||
@@ -85,7 +85,5 @@ app.get('/', function(req, res){
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, redis = require('redis')
|
||||
, app = express.createServer()
|
||||
, db = { users: [] };
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
app.use(express.bodyParser());
|
||||
|
||||
// pretend db is a database, could be
|
||||
// whatever you like
|
||||
require('./boot')(app, db);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var vm = require('vm')
|
||||
, fs = require('fs');
|
||||
|
||||
module.exports = function(app, db){
|
||||
var dir = __dirname + '/routes';
|
||||
// grab a list of our route files
|
||||
fs.readdirSync(dir).forEach(function(file){
|
||||
var str = fs.readFileSync(dir + '/' + file, 'utf8');
|
||||
// inject some pseudo globals by evaluating
|
||||
// the file with vm.runInNewContext()
|
||||
// instead of loading it with require(). require's
|
||||
// internals use similar, so dont be afraid of "boot time".
|
||||
var context = { app: app, db: db };
|
||||
// we have to merge the globals for console, process etc
|
||||
for (var key in global) context[key] = global[key];
|
||||
// note that this is essentially no different than ... just using
|
||||
// global variables, though it's only YOUR code that could influence
|
||||
// them, which is a bonus.
|
||||
vm.runInNewContext(str, context, file);
|
||||
});
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index');
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
app.redirect('user list', '/users');
|
||||
|
||||
app.get('/users', function(req, res){
|
||||
res.render('user/list', { users: db.users });
|
||||
});
|
||||
|
||||
app.get('/user/add', function(req, res){
|
||||
res.render('user/add');
|
||||
});
|
||||
|
||||
app.post('/user', function(req, res){
|
||||
var user = req.body.user;
|
||||
db.users.push(user);
|
||||
res.redirect('user list');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
res.render('user');
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
h2 Route sharing example
|
||||
ul
|
||||
li: a(href='/user/add') Add user
|
||||
li: a(href='/users') User list
|
||||
@@ -1,11 +0,0 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title Route loading example
|
||||
style
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px/1.5 solid helvetica, arial, sans-serif;
|
||||
}
|
||||
body
|
||||
#content!= body
|
||||
@@ -1,5 +0,0 @@
|
||||
h2 Add a user
|
||||
form(action='/user', method='post')
|
||||
p: input(type='text', name='user[name]', placeholder='Username')
|
||||
p: input(type='text', name='user[email]', placeholder='Email')
|
||||
p: input(type='submit', value='Add')
|
||||
@@ -1,6 +0,0 @@
|
||||
h1= user.name
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
td Email
|
||||
td= user.email
|
||||
@@ -1,5 +0,0 @@
|
||||
h1 Users
|
||||
- if (users.length)
|
||||
!= partial('user', users)
|
||||
- else
|
||||
p No users, head over to <a href='/user/add'>/user/add</a> to create one.
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -39,7 +40,7 @@ function andRestrictToSelf(req, res, next) {
|
||||
} else {
|
||||
// You may want to implement specific exceptions
|
||||
// such as UnauthorizedError or similar so that you
|
||||
// can handle these can be special-cased in an error handler
|
||||
// can handle these in app.error() specifically
|
||||
// (view ./examples/pages for this)
|
||||
next(new Error('Unauthorized'));
|
||||
}
|
||||
@@ -58,7 +59,7 @@ function andRestrictTo(role) {
|
||||
// Middleware for faux authentication
|
||||
// you would of course implement something real,
|
||||
// but this illustrates how an authenticated user
|
||||
// may interact with middleware
|
||||
// may interacte with middleware
|
||||
|
||||
app.use(function(req, res, next){
|
||||
req.authenticatedUser = users[0];
|
||||
|
||||
@@ -3,37 +3,29 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = module.exports = express();
|
||||
var app = express.createServer();
|
||||
|
||||
// create an error with .status. we
|
||||
// can then use the property in our
|
||||
// custom error handler (Connect repects this prop as well)
|
||||
|
||||
function error(status, msg) {
|
||||
var err = new Error(msg);
|
||||
err.status = status;
|
||||
return err;
|
||||
}
|
||||
// configuration
|
||||
|
||||
// if we wanted to supply more than JSON, we could
|
||||
// use something similar to the content-negotiation
|
||||
// example.
|
||||
|
||||
// here we validate the API key,
|
||||
// by mounting this middleware to /api
|
||||
// meaning only paths prefixed with "/api"
|
||||
// by mounting this middleware to /api/v1
|
||||
// meaning only paths prefixed with "/api/v1"
|
||||
// will cause this middleware to be invoked
|
||||
|
||||
app.use('/api', function(req, res, next){
|
||||
app.use('/api/v1', function(req, res, next){
|
||||
var key = req.query['api-key'];
|
||||
|
||||
// key isnt present
|
||||
if (!key) return next(error(400, 'api key required'));
|
||||
if (!key) return next(new Error('api key required'));
|
||||
|
||||
// key is invalid
|
||||
if (!~apiKeys.indexOf(key)) return next(error(401, 'invalid api key'));
|
||||
if (!~apiKeys.indexOf(key)) return next(new Error('invalid api key'));
|
||||
|
||||
// all good, store req.key for route access
|
||||
req.key = key;
|
||||
@@ -52,23 +44,39 @@ app.use(app.router);
|
||||
// regular middleware.
|
||||
app.use(function(err, req, res, next){
|
||||
// whatever you want here, feel free to populate
|
||||
// properties on `err` to treat it differently in here.
|
||||
res.send(err.status || 500, { error: err.message });
|
||||
// properties on `err` to treat it differently in here,
|
||||
// or when you next(err) set res.statusCode= etc.
|
||||
res.send({ error: err.message }, 500);
|
||||
});
|
||||
|
||||
// our custom JSON 404 middleware. Since it's placed last
|
||||
// it will be the last middleware called, if all others
|
||||
// invoke next() and do not respond.
|
||||
app.use(function(req, res){
|
||||
res.send(404, { error: "Lame, can't find that" });
|
||||
res.send({ error: "Lame, can't find that" }, 404);
|
||||
});
|
||||
|
||||
/**
|
||||
* Generate our unique identifier.
|
||||
*/
|
||||
|
||||
function uid() {
|
||||
return [
|
||||
Math.random() * 0xffff | 0
|
||||
, Math.random() * 0xffff | 0
|
||||
, Math.random() * 0xffff | 0
|
||||
, Date.now()
|
||||
].join('-');
|
||||
}
|
||||
|
||||
// map of valid api keys, typically mapped to
|
||||
// account info with some sort of database like redis.
|
||||
// api keys do _not_ serve as authentication, merely to
|
||||
// track API usage or help prevent malicious behavior etc.
|
||||
|
||||
var apiKeys = ['foo', 'bar', 'baz'];
|
||||
var apiKeys = [uid(), uid(), uid()];
|
||||
|
||||
console.log('valid keys:\n ', apiKeys.join('\n '));
|
||||
|
||||
// these two objects will serve as our faux database
|
||||
|
||||
@@ -93,15 +101,15 @@ var userRepos = {
|
||||
// we now can assume the api key is valid,
|
||||
// and simply expose the data
|
||||
|
||||
app.get('/api/users', function(req, res, next){
|
||||
app.get('/api/v1/users', function(req, res, next){
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
app.get('/api/repos', function(req, res, next){
|
||||
app.get('/api/v1/repos', function(req, res, next){
|
||||
res.send(repos);
|
||||
});
|
||||
|
||||
app.get('/api/user/:name/repos', function(req, res, next){
|
||||
app.get('/api/v1/user/:name/repos', function(req, res, next){
|
||||
var name = req.params.name
|
||||
, user = userRepos[name];
|
||||
|
||||
@@ -109,7 +117,5 @@ app.get('/api/user/:name/repos', function(req, res, next){
|
||||
else next();
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
+1
-3
@@ -1,4 +1,2 @@
|
||||
|
||||
module.exports = process.env.EXPRESS_COV
|
||||
? require('./lib-cov/express')
|
||||
: require('./lib/express');
|
||||
module.exports = require('./lib/express');
|
||||
+37
-43
@@ -9,75 +9,69 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, connect = require('connect')
|
||||
, proto = require('./application')
|
||||
var connect = require('connect')
|
||||
, HTTPSServer = require('./https')
|
||||
, HTTPServer = require('./http')
|
||||
, Route = require('./router/route')
|
||||
, Router = require('./router')
|
||||
, req = require('./request')
|
||||
, res = require('./response')
|
||||
, utils = connect.utils;
|
||||
|
||||
/**
|
||||
* Expose `createApplication()`.
|
||||
* Re-export connect auto-loaders.
|
||||
*
|
||||
* This prevents the need to `require('connect')` in order
|
||||
* to access core middleware, so for example `express.logger()` instead
|
||||
* of `require('connect').logger()`.
|
||||
*/
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
var exports = module.exports = connect.middleware;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.0.0alpha1';
|
||||
exports.version = '2.5.2';
|
||||
|
||||
/**
|
||||
* Create an express application.
|
||||
* Shortcut for `new Server(...)`.
|
||||
*
|
||||
* @return {Function}
|
||||
* @param {Function} ...
|
||||
* @return {Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
app.request = { __proto__: req };
|
||||
app.response = { __proto__: res };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose connect.middleware as express.*
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
Object.defineProperty(
|
||||
exports
|
||||
, key
|
||||
, Object.getOwnPropertyDescriptor(connect.middleware, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the prototypes.
|
||||
*/
|
||||
|
||||
exports.application = proto;
|
||||
exports.request = req;
|
||||
exports.response = res;
|
||||
exports.createServer = function(options){
|
||||
if ('object' == typeof options) {
|
||||
return new HTTPSServer(options, Array.prototype.slice.call(arguments, 1));
|
||||
} else {
|
||||
return new HTTPServer(Array.prototype.slice.call(arguments));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose constructors.
|
||||
*/
|
||||
|
||||
exports.HTTPServer = HTTPServer;
|
||||
exports.HTTPSServer = HTTPSServer;
|
||||
exports.Route = Route;
|
||||
exports.Router = Router;
|
||||
|
||||
/**
|
||||
* Expose HTTP methods.
|
||||
* View extensions.
|
||||
*/
|
||||
|
||||
exports.methods = require('./router/methods');
|
||||
exports.View =
|
||||
exports.view = require('./view');
|
||||
|
||||
/**
|
||||
* Response extensions.
|
||||
*/
|
||||
|
||||
require('./response');
|
||||
|
||||
/**
|
||||
* Request extensions.
|
||||
*/
|
||||
|
||||
require('./request');
|
||||
|
||||
// Error handler title
|
||||
|
||||
|
||||
+269
-221
@@ -1,6 +1,6 @@
|
||||
|
||||
/*!
|
||||
* Express - proto
|
||||
* Express - HTTPServer
|
||||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
* MIT Licensed
|
||||
*/
|
||||
@@ -9,120 +9,132 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
var qs = require('qs')
|
||||
, connect = require('connect')
|
||||
, router = require('./router')
|
||||
, Router = require('./router')
|
||||
, methods = Router.methods.concat('del', 'all')
|
||||
, middleware = require('./middleware')
|
||||
, debug = require('debug')('express:application')
|
||||
, View = require('./view')
|
||||
, view = require('./view')
|
||||
, toArray = require('./utils').toArray
|
||||
, methods = router.methods.concat('del', 'all')
|
||||
, url = require('url')
|
||||
, utils = connect.utils
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join
|
||||
, fs = require('fs');
|
||||
, utils = connect.utils;
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
* Expose `HTTPServer`.
|
||||
*/
|
||||
|
||||
var app = exports = module.exports = {};
|
||||
exports = module.exports = HTTPServer;
|
||||
|
||||
/**
|
||||
* Server proto.
|
||||
*/
|
||||
|
||||
var app = HTTPServer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize a new `HTTPServer` with optional `middleware`.
|
||||
*
|
||||
* @param {Array} middleware
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function HTTPServer(middleware){
|
||||
connect.HTTPServer.call(this, []);
|
||||
this.init(middleware);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from `connect.HTTPServer`.
|
||||
*/
|
||||
|
||||
app.__proto__ = connect.HTTPServer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize the server.
|
||||
*
|
||||
* - setup default configuration
|
||||
* - setup default middleware
|
||||
* - setup route reflection methods
|
||||
*
|
||||
* @param {Array} middleware
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.init = function(){
|
||||
app.init = function(middleware){
|
||||
var self = this;
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
this.viewCallbacks = [];
|
||||
this.defaultConfiguration();
|
||||
this.redirects = {};
|
||||
this.isCallbacks = {};
|
||||
this._locals = {};
|
||||
this.dynamicViewHelpers = {};
|
||||
this.errorHandlers = [];
|
||||
|
||||
// route reflection methods
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
|
||||
// expose objects to each other
|
||||
this.use(function(req, res, next){
|
||||
req.query = req.query || {};
|
||||
res.setHeader('X-Powered-By', 'Express');
|
||||
req.app = res.app = self;
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
req.next = next;
|
||||
// assign req.query
|
||||
if (req.url.indexOf('?') > 0) {
|
||||
var query = url.parse(req.url).query;
|
||||
req.query = qs.parse(query);
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// apply middleware
|
||||
if (middleware) middleware.forEach(self.use.bind(self));
|
||||
|
||||
// router
|
||||
this.routes = new Router(this);
|
||||
this.__defineGetter__('router', function(){
|
||||
this.__usedRouter = true;
|
||||
return self.routes.middleware;
|
||||
});
|
||||
|
||||
// default locals
|
||||
this.locals({
|
||||
settings: this.settings
|
||||
, app: this
|
||||
});
|
||||
|
||||
// default development configuration
|
||||
this.configure('development', function(){
|
||||
this.enable('hints');
|
||||
});
|
||||
|
||||
// default production configuration
|
||||
this.configure('production', function(){
|
||||
this.enable('view cache');
|
||||
});
|
||||
|
||||
// register error handlers on "listening"
|
||||
// so that they disregard definition position.
|
||||
this.on('listening', this.registerErrorHandlers.bind(this));
|
||||
|
||||
// route manipulation methods
|
||||
methods.forEach(function(method){
|
||||
self.lookup[method] = function(path){
|
||||
return self._router.lookup(method, path);
|
||||
return self.routes.lookup(method, path);
|
||||
};
|
||||
|
||||
self.match[method] = function(path){
|
||||
return self.routes.match(method, path);
|
||||
};
|
||||
|
||||
self.remove[method] = function(path){
|
||||
return self._router.lookup(method, path).remove();
|
||||
return self.routes.lookup(method, path).remove();
|
||||
};
|
||||
});
|
||||
|
||||
// del -> delete
|
||||
self.lookup.del = self.lookup.delete;
|
||||
self.match.del = self.match.delete;
|
||||
self.remove.del = self.remove.delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize application configuration.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.defaultConfiguration = function(){
|
||||
var self = this;
|
||||
|
||||
// default settings
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
this.use(middleware.init(this));
|
||||
|
||||
// app locals
|
||||
this.locals = function(obj){
|
||||
for (var key in obj) self.locals[key] = obj[key];
|
||||
return self;
|
||||
};
|
||||
|
||||
// response locals
|
||||
this.locals.use = function(fn){
|
||||
if (3 == fn.length) {
|
||||
self.viewCallbacks.push(fn);
|
||||
} else {
|
||||
self.viewCallbacks.push(function(req, res, done){
|
||||
fn(req, res);
|
||||
done();
|
||||
});
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
// router
|
||||
this._router = new Router(this);
|
||||
this.routes = this._router.routes;
|
||||
this.__defineGetter__('router', function(){
|
||||
this._usedRouter = true;
|
||||
this._router.caseSensitive = this.enabled('case sensitive routing');
|
||||
this._router.strict = this.enabled('strict routing');
|
||||
return this._router.middleware;
|
||||
});
|
||||
|
||||
// default locals
|
||||
this.locals.settings = this.settings;
|
||||
|
||||
// default configuration
|
||||
this.enable('jsonp callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
this.set('json spaces', 2);
|
||||
});
|
||||
|
||||
this.configure('production', function(){
|
||||
this.enable('view cache');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove routes matching the given `path`.
|
||||
*
|
||||
@@ -132,45 +144,82 @@ app.defaultConfiguration = function(){
|
||||
*/
|
||||
|
||||
app.remove = function(path){
|
||||
return this._router.lookup('all', path).remove();
|
||||
return this.routes.lookup('all', path).remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup routes defined with a path
|
||||
* equivalent to `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Stirng} path
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.lookup = function(path){
|
||||
return this._router.lookup('all', path);
|
||||
return this.routes.lookup('all', path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect#use()` to apply settings to
|
||||
* mounted applications.
|
||||
* Lookup routes matching the given `url`.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} fn
|
||||
* @return {app} for chaining
|
||||
* @param {Stirng} url
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.use = function(route, fn){
|
||||
var app, home, handle;
|
||||
app.match = function(url){
|
||||
return this.routes.match('all', url);
|
||||
};
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) fn = route, route = '/';
|
||||
/**
|
||||
* When using the vhost() middleware register error handlers.
|
||||
*/
|
||||
|
||||
app.onvhost = function(){
|
||||
this.registerErrorHandlers();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register error handlers.
|
||||
*
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.registerErrorHandlers = function(){
|
||||
this.errorHandlers.forEach(function(fn){
|
||||
this.use(function(err, req, res, next){
|
||||
fn.apply(this, arguments);
|
||||
});
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect.HTTPServer#use()` to apply settings to
|
||||
* mounted applications.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} middleware
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.use = function(route, middleware){
|
||||
var app, base, handle;
|
||||
|
||||
if ('string' != typeof route) {
|
||||
middleware = route, route = '/';
|
||||
}
|
||||
|
||||
// express app
|
||||
if (fn.handle && fn.set) app = fn;
|
||||
if (middleware.handle && middleware.set) app = middleware;
|
||||
|
||||
// restore .app property on req and res
|
||||
if (app) {
|
||||
app.route = route;
|
||||
fn = function(req, res, next) {
|
||||
middleware = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
@@ -179,38 +228,86 @@ app.use = function(route, fn){
|
||||
};
|
||||
}
|
||||
|
||||
connect.proto.use.call(this, route, fn);
|
||||
connect.HTTPServer.prototype.use.call(this, route, middleware);
|
||||
|
||||
// mounted an app
|
||||
// mounted an app, invoke the hook
|
||||
// and adjust some settings
|
||||
if (app) {
|
||||
base = this.set('basepath') || this.route;
|
||||
if ('/' == base) base = '';
|
||||
base = base + (app.set('basepath') || app.route);
|
||||
app.set('basepath', base);
|
||||
app.parent = this;
|
||||
app.emit('mount', this);
|
||||
if (app.__mounted) app.__mounted.call(app, this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given template engine callback `fn`
|
||||
* as `ext`. For example we may wish to map ".html"
|
||||
* files to ejs rather than using the ".ejs" extension.
|
||||
* Assign a callback `fn` which is called
|
||||
* when this `Server` is passed to `Server#use()`.
|
||||
*
|
||||
* app.engine('.html', require('ejs').render);
|
||||
* Examples:
|
||||
*
|
||||
* or
|
||||
* var app = express.createServer()
|
||||
* , blog = express.createServer();
|
||||
*
|
||||
* app.engine('html', require('ejs').render);
|
||||
* blog.mounted(function(parent){
|
||||
* // parent is app
|
||||
* // "this" is blog
|
||||
* });
|
||||
*
|
||||
* app.use(blog);
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.engine = function(ext, fn){
|
||||
if ('function' != typeof fn) throw new Error('callback function required');
|
||||
if ('.' != ext[0]) ext = '.' + ext;
|
||||
this.engines[ext] = fn;
|
||||
app.mounted = function(fn){
|
||||
this.__mounted = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* See: view.register.
|
||||
*
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.register = function(){
|
||||
view.register.apply(this, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given view helpers `obj`. This method
|
||||
* can be called several times to apply additional helpers.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.helpers =
|
||||
app.locals = function(obj){
|
||||
utils.merge(this._locals, obj);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given dynamic view helpers `obj`. This method
|
||||
* can be called several times to apply additional helpers.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.dynamicHelpers = function(obj){
|
||||
utils.merge(this.dynamicViewHelpers, obj);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -269,7 +366,7 @@ app.engine = function(ext, fn){
|
||||
*
|
||||
* @param {String|Array|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -286,18 +383,47 @@ app.param = function(name, fn){
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this._router.param(name);
|
||||
this.routes.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
fns.forEach(function(fn){
|
||||
self._router.param(name, fn);
|
||||
self.routes.param(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign a custom exception handler callback `fn`.
|
||||
* These handlers are always _last_ in the middleware stack.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.error = function(fn){
|
||||
this.errorHandlers.push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given callback `fn` for the given `type`.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.is = function(type, fn){
|
||||
if (!fn) return this.isCallbacks[type];
|
||||
this.isCallbacks[type] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign `setting` to `val`, or return `setting`'s value.
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
@@ -309,7 +435,7 @@ app.param = function(name, fn){
|
||||
*/
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
if (val === undefined) {
|
||||
if (this.settings.hasOwnProperty(setting)) {
|
||||
return this.settings[setting];
|
||||
} else if (this.parent) {
|
||||
@@ -321,21 +447,6 @@ app.set = function(setting, val){
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the app's absolute pathname
|
||||
* based on the parent(s) that have
|
||||
* mounted it.
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.path = function(){
|
||||
return this.parent
|
||||
? this.parent.path() + this.route
|
||||
: '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is enabled.
|
||||
*
|
||||
@@ -364,7 +475,7 @@ app.disabled = function(setting){
|
||||
* Enable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -376,7 +487,7 @@ app.enable = function(setting){
|
||||
* Disable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -384,6 +495,20 @@ app.disable = function(setting){
|
||||
return this.set(setting, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect `key` to `url`.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {String} url
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.redirect = function(key, url){
|
||||
this.redirects[key] = url;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for zero or more envs,
|
||||
* when no env is specified that callback will
|
||||
@@ -406,44 +531,29 @@ app.disable = function(setting){
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
var envs = 'all'
|
||||
, args = [].slice.call(arguments);
|
||||
, args = toArray(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for connections.
|
||||
*
|
||||
* This method takes the same arguments
|
||||
* as node's `http.Server#listen()`.
|
||||
*
|
||||
* @return {http.Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.listen = function(){
|
||||
var server = http.createServer(this);
|
||||
return server.listen.apply(server, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
return this._router.route.apply(this._router, args);
|
||||
if (1 == arguments.length) return this.routes.lookup(method, path);
|
||||
var args = [method].concat(toArray(arguments));
|
||||
if (!this.__usedRouter) this.use(this.router);
|
||||
return this.routes._route.apply(this.routes, args);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -453,14 +563,15 @@ methods.forEach(function(method){
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @return {app} for chaining
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.all = function(path){
|
||||
var args = arguments;
|
||||
if (1 == args.length) return this.routes.lookup('all', path);
|
||||
methods.forEach(function(method){
|
||||
if ('all' == method || 'del' == method) return;
|
||||
if ('all' == method) return;
|
||||
app[method].apply(this, args);
|
||||
}, this);
|
||||
return this;
|
||||
@@ -470,66 +581,3 @@ app.all = function(path){
|
||||
|
||||
app.del = app.delete;
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
* and a callback accepting an error and the
|
||||
* rendered template string.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Function} options or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.render = function(name, options, fn){
|
||||
var self = this
|
||||
, opts = {}
|
||||
, cache = this.cache
|
||||
, engines = this.engines
|
||||
, view;
|
||||
|
||||
// support callback function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options, options = {};
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
|
||||
// merge options.locals
|
||||
if (options.locals) utils.merge(opts, options.locals);
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
? this.enabled('view cache')
|
||||
: opts.cache;
|
||||
|
||||
// primed cache
|
||||
if (opts.cache) view = cache[name];
|
||||
|
||||
// view
|
||||
if (!view) {
|
||||
view = new View(name, {
|
||||
defaultEngine: this.get('view engine')
|
||||
, root: this.get('views') || process.cwd() + '/views'
|
||||
, engines: engines
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
return fn(new Error('Failed to lookup view "' + name + '"'));
|
||||
}
|
||||
|
||||
// prime the cache
|
||||
if (opts.cache) cache[name] = view;
|
||||
}
|
||||
|
||||
// render
|
||||
try {
|
||||
view.render(opts, fn);
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
};
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário