mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 18:15:04 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@ lib-cov
|
||||
benchmarks/graphs
|
||||
testing.js
|
||||
node_modules/
|
||||
testing
|
||||
|
||||
56
History.md
56
History.md
@@ -1,4 +1,60 @@
|
||||
|
||||
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 support for multiple callbacks for `app.param()`. Closes #801
|
||||
Closes #805
|
||||
* Changed: removed .call(self) for route callbacks
|
||||
* Dependency: `qs >= 0.3.1`
|
||||
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808
|
||||
|
||||
2.4.4 / 2011-08-05
|
||||
==================
|
||||
|
||||
* Fixed `res.header()` intention of a set, even when `undefined`
|
||||
* Fixed `*`, value no longer required
|
||||
* Fixed `res.send(204)` support. Closes #771
|
||||
|
||||
2.4.3 / 2011-07-14
|
||||
==================
|
||||
|
||||
|
||||
12
Makefile
12
Makefile
@@ -1,16 +1,10 @@
|
||||
|
||||
DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
HTMLDOCS = $(DOCS:.md=.html)
|
||||
TESTS = $(shell find test/*.test.js)
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso \
|
||||
-I lib \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso $(TESTS)
|
||||
|
||||
docs: $(HTMLDOCS)
|
||||
@ echo "... generating TOC"
|
||||
@@ -32,4 +26,4 @@ site:
|
||||
docclean:
|
||||
rm -f docs/*.{1,html}
|
||||
|
||||
.PHONY: site test test-cov docs docclean
|
||||
.PHONY: site test docs docclean
|
||||
@@ -95,7 +95,9 @@ The following are the major contributors of Express (in no specific order).
|
||||
|
||||
Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
|
||||
Express 2.x is compatible with node 0.4.x and connect 1.x
|
||||
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
|
||||
|
||||
|
||||
128
bin/express
128
bin/express
@@ -5,13 +5,14 @@
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, exec = require('child_process').exec;
|
||||
, exec = require('child_process').exec
|
||||
, mkdirp = require('mkdirp');
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.4.3';
|
||||
var version = '2.5.2';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
@@ -42,11 +43,26 @@ var usage = ''
|
||||
+ ' 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 (less|sass|stylus). default=plain css\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.
|
||||
*/
|
||||
|
||||
var index = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET home page.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' })'
|
||||
, '};'
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
@@ -58,7 +74,7 @@ var jadeLayout = [
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body!= body'
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
@@ -67,7 +83,7 @@ var jadeLayout = [
|
||||
var jadeIndex = [
|
||||
'h1= title'
|
||||
, 'p Welcome to #{title}'
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* EJS layout template.
|
||||
@@ -84,7 +100,7 @@ var ejsLayout = [
|
||||
, ' <%- body %>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
@@ -93,7 +109,7 @@ var ejsLayout = [
|
||||
var ejsIndex = [
|
||||
'<h1><%= title %></h1>'
|
||||
, '<p>Welcome to <%= title %></p>'
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
@@ -108,34 +124,7 @@ var css = [
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
*/
|
||||
|
||||
var less = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join('\n');
|
||||
|
||||
/**
|
||||
* Default sass template.
|
||||
*/
|
||||
|
||||
var sass = [
|
||||
'body'
|
||||
, ' :padding 50px'
|
||||
, ' :font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' :color #00B7FF'
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
@@ -143,11 +132,11 @@ var sass = [
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding 50px'
|
||||
, ' font 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color #00B7FF'
|
||||
].join('\n');
|
||||
, ' color: #00B7FF'
|
||||
].join('\r\n');
|
||||
|
||||
/**
|
||||
* App template.
|
||||
@@ -159,7 +148,8 @@ var app = [
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ''
|
||||
, 'var app = module.exports = express.createServer();'
|
||||
, ''
|
||||
@@ -184,16 +174,12 @@ var app = [
|
||||
, ''
|
||||
, '// Routes'
|
||||
, ''
|
||||
, 'app.get(\'/\', function(req, res){'
|
||||
, ' res.render(\'index\', {'
|
||||
, ' title: \'Express\''
|
||||
, ' });'
|
||||
, '});'
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, ''
|
||||
, 'app.listen(3000);'
|
||||
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
|
||||
, ''
|
||||
].join('\n');
|
||||
].join('\r\n');
|
||||
|
||||
// Parse arguments
|
||||
|
||||
@@ -259,7 +245,16 @@ while (args.length) {
|
||||
*/
|
||||
|
||||
function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' dont forget to install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
});
|
||||
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/public');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
@@ -267,16 +262,15 @@ function createApplicationAt(path) {
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
case 'less':
|
||||
write(path + '/public/stylesheets/style.less', less);
|
||||
break;
|
||||
case 'sass':
|
||||
write(path + '/public/stylesheets/style.sass', sass);
|
||||
break;
|
||||
default:
|
||||
write(path + '/public/stylesheets/style.css', css);
|
||||
}
|
||||
});
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (templateEngine) {
|
||||
case 'ejs':
|
||||
@@ -292,12 +286,8 @@ function createApplicationAt(path) {
|
||||
|
||||
// CSS Engine support
|
||||
switch (cssEngine) {
|
||||
case 'sass':
|
||||
case 'less':
|
||||
app = app.replace('{css}', '\n app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'' + cssEngine + '\'] }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', '\n 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}', '');
|
||||
@@ -305,22 +295,22 @@ function createApplicationAt(path) {
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', sessions
|
||||
? '\n app.use(express.cookieParser());\n app.use(express.session({ secret: \'your secret here\' }));'
|
||||
? '\r\n app.use(express.cookieParser());\r\n app.use(express.session({ secret: \'your secret here\' }));'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', templateEngine);
|
||||
|
||||
// package.json
|
||||
var json = '{\n';
|
||||
json += ' "name": "application-name"\n';
|
||||
json += ' , "version": "0.0.1"\n';
|
||||
json += ' , "private": true\n';
|
||||
json += ' , "dependencies": {\n';
|
||||
json += ' "express": "' + version + '"\n';
|
||||
if (cssEngine) json += ' , "' + cssEngine + '": ">= 0.0.1"\n';
|
||||
if (templateEngine) json += ' , "' + templateEngine + '": ">= 0.0.1"\n';
|
||||
json += ' }\n';
|
||||
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 += '}';
|
||||
|
||||
|
||||
@@ -398,9 +388,9 @@ function prompt(msg, fn) {
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
exec('mkdir -p ' + path, function(err){
|
||||
mkdirp(path, 0755, function(err){
|
||||
if (err) throw err;
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
console.log(' \033[36mcreate\033[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ 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
|
||||
@@ -947,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
|
||||
@@ -972,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');
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,6 +1,8 @@
|
||||
!!!
|
||||
doctype 5
|
||||
html
|
||||
head
|
||||
title Jade Example
|
||||
block title
|
||||
title Jade Example
|
||||
link(rel="stylesheet", href="/stylesheets/style.css")
|
||||
body!= body
|
||||
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
|
||||
26
examples/json-config/app.js
Normal file
26
examples/json-config/app.js
Normal file
@@ -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);
|
||||
19
examples/json-config/config.js
Normal file
19
examples/json-config/config.js
Normal file
@@ -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 = {
|
||||
|
||||
};
|
||||
4
examples/json-config/views/index.jade
Normal file
4
examples/json-config/views/index.jade
Normal file
@@ -0,0 +1,4 @@
|
||||
html
|
||||
body
|
||||
h1 #{settings.title}
|
||||
p Simple example
|
||||
@@ -28,7 +28,7 @@ var exports = module.exports = connect.middleware;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '2.4.3';
|
||||
exports.version = '2.5.2';
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
|
||||
57
lib/http.js
57
lib/http.js
@@ -66,7 +66,6 @@ app.init = function(middleware){
|
||||
this.dynamicViewHelpers = {};
|
||||
this.errorHandlers = [];
|
||||
|
||||
this.set('home', '/');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
|
||||
// expose objects to each other
|
||||
@@ -208,7 +207,7 @@ app.registerErrorHandlers = function(){
|
||||
*/
|
||||
|
||||
app.use = function(route, middleware){
|
||||
var app, home, handle;
|
||||
var app, base, handle;
|
||||
|
||||
if ('string' != typeof route) {
|
||||
middleware = route, route = '/';
|
||||
@@ -234,9 +233,10 @@ app.use = function(route, middleware){
|
||||
// mounted an app, invoke the hook
|
||||
// and adjust some settings
|
||||
if (app) {
|
||||
home = app.set('home');
|
||||
if ('/' == home) home = '';
|
||||
app.set('home', app.route + home);
|
||||
base = this.set('basepath') || this.route;
|
||||
if ('/' == base) base = '';
|
||||
base = base + (app.set('basepath') || app.route);
|
||||
app.set('basepath', base);
|
||||
app.parent = this;
|
||||
if (app.__mounted) app.__mounted.call(app, this);
|
||||
}
|
||||
@@ -312,7 +312,7 @@ app.dynamicHelpers = function(obj){
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback `fn`.
|
||||
* Map the given param placeholder `name`(s) to the given callback(s).
|
||||
*
|
||||
* Param mapping is used to provide pre-conditions to routes
|
||||
* which us normalized placeholders. This callback has the same
|
||||
@@ -332,6 +332,38 @@ app.dynamicHelpers = function(obj){
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* Passing a single function allows you to map logic
|
||||
* to the values passed to `app.param()`, for example
|
||||
* this is useful to provide coercion support in a concise manner.
|
||||
*
|
||||
* The following example maps regular expressions to param values
|
||||
* ensuring that they match, otherwise passing control to the next
|
||||
* route:
|
||||
*
|
||||
* app.param(function(name, regexp){
|
||||
* if (regexp instanceof RegExp) {
|
||||
* return function(req, res, next, val){
|
||||
* var captures;
|
||||
* if (captures = regexp.exec(String(val))) {
|
||||
* req.params[name] = captures;
|
||||
* next();
|
||||
* } else {
|
||||
* next('route');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* We can now use it as shown below, where "/commit/:commit" expects
|
||||
* that the value for ":commit" is at 5 or more digits. The capture
|
||||
* groups are then available as `req.params.commit` as we defined
|
||||
* in the function above.
|
||||
*
|
||||
* app.param('commit', /^\d{5,}$/);
|
||||
*
|
||||
* For more of this useful functionality take a look
|
||||
* at [express-params](http://github.com/visionmedia/express-params).
|
||||
*
|
||||
* @param {String|Array|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {Server} for chaining
|
||||
@@ -339,18 +371,25 @@ app.dynamicHelpers = function(obj){
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this
|
||||
, fns = [].slice.call(arguments, 1);
|
||||
|
||||
// array
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(name){
|
||||
this.param(name, fn);
|
||||
}, this);
|
||||
fns.forEach(function(fn){
|
||||
self.param(name, fn);
|
||||
});
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this.routes.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
this.routes.param(name, fn);
|
||||
fns.forEach(function(fn){
|
||||
self.routes.param(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var http = require('http')
|
||||
, req = http.IncomingMessage.prototype
|
||||
, utils = require('./utils')
|
||||
, parse = require('url').parse
|
||||
, mime = require('mime');
|
||||
|
||||
/**
|
||||
@@ -87,6 +88,17 @@ req.get = function(field, param){
|
||||
return RegExp.$1 || RegExp.$2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Short-hand for `require('url').parse(req.url).pathname`.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('path', function(){
|
||||
return parse(this.url).pathname;
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the _Accept_ header is present, and includes the given `type`.
|
||||
*
|
||||
@@ -217,10 +229,10 @@ req.flash = function(type, msg){
|
||||
, args = arguments
|
||||
, formatters = this.app.flashFormatters || {};
|
||||
formatters.__proto__ = flashFormatters;
|
||||
msg = utils.miniMarkdown(utils.escape(msg));
|
||||
msg = utils.miniMarkdown(msg);
|
||||
msg = msg.replace(/%([a-zA-Z])/g, function(_, format){
|
||||
var formatter = formatters[format];
|
||||
if (formatter) return formatter(args[i++]);
|
||||
if (formatter) return formatter(utils.escape(args[i++]));
|
||||
});
|
||||
return (msgs[type] = msgs[type] || []).push(msg);
|
||||
} else if (type) {
|
||||
|
||||
@@ -52,7 +52,7 @@ res.send = function(body, headers, status){
|
||||
status = status || this.statusCode;
|
||||
|
||||
// allow 0 args as 204
|
||||
if (!arguments.length || undefined === body) body = status = 204;
|
||||
if (!arguments.length || undefined === body) status = 204;
|
||||
|
||||
// determine content type
|
||||
switch (typeof body) {
|
||||
@@ -81,7 +81,7 @@ res.send = function(body, headers, status){
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (!this.header('Content-Length')) {
|
||||
if (undefined !== body && !this.header('Content-Length')) {
|
||||
this.header('Content-Length', Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
@@ -100,11 +100,12 @@ res.send = function(body, headers, status){
|
||||
if (204 == status || 304 == status) {
|
||||
this.removeHeader('Content-Type');
|
||||
this.removeHeader('Content-Length');
|
||||
body = '';
|
||||
}
|
||||
|
||||
// respond
|
||||
this.statusCode = status;
|
||||
this.end('HEAD' == this.req.method ? undefined : body);
|
||||
this.end('HEAD' == this.req.method ? null : body);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -270,17 +271,14 @@ res.download = function(path, filename, fn, fn2){
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} val
|
||||
* @return {String}
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.header = function(name, val){
|
||||
if (val === undefined) {
|
||||
return this.getHeader(name);
|
||||
} else {
|
||||
this.setHeader(name, val);
|
||||
return val;
|
||||
}
|
||||
if (1 == arguments.length) return this.getHeader(name);
|
||||
this.setHeader(name, val);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -304,7 +302,7 @@ res.clearCookie = function(name, options){
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` max-age in milliseconds, converted to `expires`
|
||||
* - `path` defaults to the "home" setting which is typically "/"
|
||||
* - `path` defaults to the "basepath" setting which is typically "/"
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
@@ -323,7 +321,7 @@ res.clearCookie = function(name, options){
|
||||
res.cookie = function(name, val, options){
|
||||
options = options || {};
|
||||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
|
||||
if (undefined === options.path) options.path = this.app.set('home');
|
||||
if (undefined === options.path) options.path = this.app.set('basepath');
|
||||
var cookie = utils.serializeCookie(name, val, options);
|
||||
this.header('Set-Cookie', cookie);
|
||||
};
|
||||
@@ -335,8 +333,8 @@ res.cookie = function(name, val, options){
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
* to the _Referrer_ or _Referer_ headers or the application's
|
||||
* "home" setting. Express also supports "home" out of the box,
|
||||
* which can be set via `app.set('home', '/blog');`, and defaults
|
||||
* "basepath" setting. Express also supports "basepath" out of the box,
|
||||
* which can be set via `app.set('basepath', '/blog');`, and defaults
|
||||
* to '/'.
|
||||
*
|
||||
* Redirect Mapping:
|
||||
@@ -376,8 +374,9 @@ res.cookie = function(name, val, options){
|
||||
res.redirect = function(url, status){
|
||||
var app = this.app
|
||||
, req = this.req
|
||||
, base = app.set('home') || '/'
|
||||
, base = app.set('basepath') || app.route
|
||||
, status = status || 302
|
||||
, head = 'HEAD' == req.method
|
||||
, body;
|
||||
|
||||
// Setup redirect map
|
||||
@@ -400,14 +399,13 @@ res.redirect = function(url, status){
|
||||
// Relative
|
||||
if (!~url.indexOf('://')) {
|
||||
// Respect mount-point
|
||||
if (app.route) url = join(app.route, url);
|
||||
if ('/' != base && 0 != url.indexOf(base)) url = base + url;
|
||||
|
||||
// Absolute
|
||||
var host = req.headers.host
|
||||
, tls = req.connection.encrypted;
|
||||
url = 'http' + (tls ? 's' : '') + '://' + host + url;
|
||||
}
|
||||
|
||||
|
||||
// Support text/{plain,html} by default
|
||||
if (req.accepts('html')) {
|
||||
@@ -421,7 +419,7 @@ res.redirect = function(url, status){
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.header('Location', url);
|
||||
this.end(body);
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,10 +79,23 @@ Router.prototype.param = function(name, fn){
|
||||
throw new Error('invalid param() call for ' + name + ', got ' + fn);
|
||||
}
|
||||
|
||||
this.params[name] = fn;
|
||||
(this.params[name] = this.params[name] || []).push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a `Collection` of all routes defined.
|
||||
*
|
||||
* @return {Collection}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.all = function(){
|
||||
return this.find(function(){
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the given `route`, returns
|
||||
* a bool indicating if the route was present
|
||||
@@ -182,14 +195,18 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
, self = this;
|
||||
|
||||
// route dispatch
|
||||
(function pass(i){
|
||||
var route
|
||||
(function pass(i, err){
|
||||
var paramCallbacks
|
||||
, paramIndex = 0
|
||||
, paramVal
|
||||
, route
|
||||
, keys
|
||||
, key
|
||||
, ret;
|
||||
|
||||
// match next route
|
||||
function nextRoute() {
|
||||
pass(req._route_index + 1);
|
||||
function nextRoute(err) {
|
||||
pass(req._route_index + 1, err);
|
||||
}
|
||||
|
||||
// match route
|
||||
@@ -199,7 +216,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
|
||||
|
||||
// no route
|
||||
if (!route) return next();
|
||||
if (!route) return next(err);
|
||||
|
||||
// we have a route
|
||||
// start at param 0
|
||||
@@ -207,50 +224,58 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
keys = route.keys;
|
||||
i = 0;
|
||||
|
||||
(function param(err) {
|
||||
var key = keys[i++]
|
||||
, val = key && req.params[key.name]
|
||||
, fn = key && params[key.name]
|
||||
, ret;
|
||||
// param callbacks
|
||||
function param(err) {
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
paramVal = key && req.params[key.name];
|
||||
paramCallbacks = key && params[key.name];
|
||||
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err) {
|
||||
next(err);
|
||||
} else if (fn && undefined !== val) {
|
||||
fn(req, res, param, val);
|
||||
i = 0;
|
||||
callbacks(err);
|
||||
} else if (paramCallbacks && undefined !== paramVal) {
|
||||
paramCallback();
|
||||
} else if (key) {
|
||||
param();
|
||||
} else {
|
||||
i = 0;
|
||||
middleware();
|
||||
callbacks();
|
||||
}
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
})();
|
||||
|
||||
// invoke route middleware
|
||||
function middleware(err) {
|
||||
var fn = route.middleware[i++];
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err) {
|
||||
next(err);
|
||||
} else if (fn) {
|
||||
fn(req, res, middleware);
|
||||
} else {
|
||||
done();
|
||||
param(err);
|
||||
}
|
||||
};
|
||||
|
||||
// invoke middleware callback
|
||||
function done() {
|
||||
route.callback.call(self, req, res, function(err){
|
||||
if (err) return next(err);
|
||||
pass(req._route_index + 1);
|
||||
});
|
||||
param(err);
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
if (err || !fn) return param(err);
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
}
|
||||
|
||||
// invoke route callbacks
|
||||
function callbacks(err) {
|
||||
var fn = route.callbacks[i++];
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err && fn) {
|
||||
if (fn.length < 4) return callbacks(err);
|
||||
fn(err, req, res, callbacks);
|
||||
} else if (fn) {
|
||||
fn(req, res, callbacks);
|
||||
} else {
|
||||
nextRoute(err);
|
||||
}
|
||||
} catch (err) {
|
||||
callbacks(err);
|
||||
}
|
||||
}
|
||||
})(0);
|
||||
};
|
||||
@@ -344,37 +369,26 @@ Router.prototype._match = function(req, i){
|
||||
};
|
||||
|
||||
/**
|
||||
* Route `method`, `path`, and optional middleware
|
||||
* to the callback `fn`.
|
||||
* Route `method`, `path`, and one or more callbacks.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @param {Function} fn
|
||||
* @param {Function} callback...
|
||||
* @return {Router} for chaining
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._route = function(method, path, fn){
|
||||
Router.prototype._route = function(method, path, callbacks){
|
||||
var app = this.app
|
||||
, middleware = [];
|
||||
, callbacks = utils.flatten(toArray(arguments, 2));
|
||||
|
||||
// slice middleware
|
||||
if (arguments.length > 3) {
|
||||
middleware = toArray(arguments, 2);
|
||||
fn = middleware.pop();
|
||||
middleware = utils.flatten(middleware);
|
||||
}
|
||||
|
||||
// ensure path and callback are given
|
||||
if (!path) throw new Error(method + 'route requires a path');
|
||||
if (!fn) throw new Error(method + ' route ' + path + ' requires a callback');
|
||||
// ensure path was given
|
||||
if (!path) throw new Error('app.' + method + '() requires a path');
|
||||
|
||||
// create the route
|
||||
var route = new Route(method, path, fn, {
|
||||
var route = new Route(method, path, callbacks, {
|
||||
sensitive: app.enabled('case sensitive routes')
|
||||
, strict: app.enabled('strict routing')
|
||||
, middleware: middleware
|
||||
});
|
||||
|
||||
// add it
|
||||
|
||||
@@ -13,27 +13,25 @@ module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and callback `fn` and `options`.
|
||||
* and an array of `callbacks` and `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `strict` enable strict matching for trailing slashes
|
||||
* - `middleware` array of middleware
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
* @param {Array} callbacks
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, fn, options) {
|
||||
function Route(method, path, callbacks, options) {
|
||||
options = options || {};
|
||||
this.callback = fn;
|
||||
this.path = path;
|
||||
this.method = method;
|
||||
this.middleware = options.middleware;
|
||||
this.callbacks = callbacks;
|
||||
this.regexp = normalize(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
@@ -81,10 +79,10 @@ function normalize(path, keys, sensitive, strict) {
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (format || '') + (capture || '([^/]+?)') + ')'
|
||||
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.+)');
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
}
|
||||
|
||||
13
lib/utils.js
13
lib/utils.js
@@ -5,6 +5,19 @@
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if `path` looks absolute.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Merge object `b` with `a` giving precedence to
|
||||
* values in object `a`.
|
||||
|
||||
@@ -179,8 +179,6 @@ function renderPartial(res, view, options, parentLocals, parent){
|
||||
options[name] = object;
|
||||
} else if (name === global) {
|
||||
merge(options, object);
|
||||
} else {
|
||||
options.scope = object;
|
||||
}
|
||||
}
|
||||
return res.render(view, options, null, parent, true);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
var path = require('path')
|
||||
, utils = require('../utils')
|
||||
, extname = path.extname
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
@@ -99,7 +100,7 @@ View.prototype.resolvePath = function(){
|
||||
// Implicit engine
|
||||
if (!~this.basename.indexOf('.')) path += this.extension;
|
||||
// Absolute
|
||||
if ('/' == path[0]) return path;
|
||||
if (utils.isAbsolute(path)) return path;
|
||||
// Relative to parent
|
||||
if (this.relative && this.parent) return this.parent.dirname + '/' + path;
|
||||
// Relative to root
|
||||
|
||||
15
package.json
15
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "2.4.3",
|
||||
"version": "2.5.2",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
@@ -10,18 +10,19 @@
|
||||
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": ">= 1.5.2 < 2.0.0",
|
||||
"connect": "1.8.x",
|
||||
"mime": ">= 0.0.1",
|
||||
"qs": ">= 0.0.6"
|
||||
"qs": ">= 0.3.1",
|
||||
"mkdirp": "0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"connect-form": "0.2.1",
|
||||
"ejs": "0.4.2",
|
||||
"expresso": "0.7.2",
|
||||
"expresso": "0.9.2",
|
||||
"hamljs": "0.5.1",
|
||||
"jade": "0.11.0",
|
||||
"jade": "0.16.2",
|
||||
"stylus": "0.13.0",
|
||||
"should": "0.2.1",
|
||||
"should": "0.3.2",
|
||||
"express-messages": "0.0.2",
|
||||
"node-markdown": ">= 0.0.1",
|
||||
"connect-redis": ">= 0.0.1"
|
||||
@@ -34,5 +35,5 @@
|
||||
"test": "make test",
|
||||
"prepublish" : "npm prune"
|
||||
},
|
||||
"engines": { "node": ">= 0.4.1 < 0.5.0" }
|
||||
"engines": { "node": ">= 0.4.1 < 0.7.0" }
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express')
|
||||
var express = require('../')
|
||||
, connect = require('connect')
|
||||
, assert = require('assert')
|
||||
, should = require('should')
|
||||
@@ -37,22 +37,22 @@ module.exports = {
|
||||
|
||||
'test basic server': function(){
|
||||
var server = express.createServer();
|
||||
|
||||
|
||||
server.get('/', function(req, res){
|
||||
server.set('env').should.equal('test');
|
||||
res.writeHead(200, {});
|
||||
res.end('wahoo');
|
||||
});
|
||||
|
||||
|
||||
server.put('/user/:id', function(req, res){
|
||||
res.writeHead(200, {});
|
||||
res.end('updated user ' + req.params.id)
|
||||
});
|
||||
|
||||
|
||||
server.del('/something', function(req, res){
|
||||
res.send('Destroyed');
|
||||
});
|
||||
|
||||
|
||||
server.delete('/something/else', function(req, res){
|
||||
res.send('Destroyed');
|
||||
});
|
||||
@@ -61,7 +61,7 @@ module.exports = {
|
||||
req.staff = { id: req.params.id };
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
server.get('/staff/:id', function(req, res){
|
||||
res.send('GET Staff ' + req.staff.id);
|
||||
});
|
||||
@@ -73,7 +73,7 @@ module.exports = {
|
||||
server.all('*', function(req, res){
|
||||
res.send('requested ' + req.url);
|
||||
});
|
||||
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/' },
|
||||
{ body: 'wahoo' });
|
||||
@@ -81,15 +81,15 @@ module.exports = {
|
||||
assert.response(server,
|
||||
{ url: '/user/12', method: 'PUT' },
|
||||
{ body: 'updated user 12' });
|
||||
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/something', method: 'DELETE' },
|
||||
{ body: 'Destroyed' });
|
||||
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/something/else', method: 'DELETE' },
|
||||
{ body: 'Destroyed' });
|
||||
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/staff/12' },
|
||||
{ body: 'GET Staff 12' });
|
||||
@@ -105,17 +105,17 @@ module.exports = {
|
||||
|
||||
'test constructor middleware': function(beforeExit){
|
||||
var calls = [];
|
||||
|
||||
|
||||
function one(req, res, next){
|
||||
calls.push('one');
|
||||
next();
|
||||
}
|
||||
|
||||
|
||||
function two(req, res, next){
|
||||
calls.push('two');
|
||||
next();
|
||||
}
|
||||
|
||||
|
||||
var app = express.createServer(one, two);
|
||||
app.get('/', function(req, res){
|
||||
res.writeHead(200, {});
|
||||
@@ -144,14 +144,14 @@ module.exports = {
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'Internal Server Error' });
|
||||
|
||||
|
||||
// Custom handler
|
||||
var app = express.createServer();
|
||||
|
||||
app.error(function(err, req, res){
|
||||
res.send('Shit: ' + err.message, 500);
|
||||
});
|
||||
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
next(new Error('broken'));
|
||||
});
|
||||
@@ -174,7 +174,7 @@ module.exports = {
|
||||
app.error(function(err, req, res, next){
|
||||
res.send(err.message, 500);
|
||||
});
|
||||
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
throw new Error('broken');
|
||||
});
|
||||
@@ -220,7 +220,7 @@ module.exports = {
|
||||
|
||||
'test #use()': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.get('/users', function(req, res, next){
|
||||
next(new Error('fail!!'));
|
||||
});
|
||||
@@ -244,13 +244,13 @@ module.exports = {
|
||||
}).configure('production', function(){
|
||||
calls.push('production');
|
||||
});
|
||||
|
||||
|
||||
should.equal(ret, server, 'Test #configure() returns server for chaining');
|
||||
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/' },
|
||||
{ body: 'Cannot GET /' });
|
||||
|
||||
|
||||
beforeExit(function(){
|
||||
calls.should.eql(['any', 'dev']);
|
||||
});
|
||||
@@ -258,7 +258,7 @@ module.exports = {
|
||||
|
||||
'test #configure() immediate call': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.configure(function(){
|
||||
app.use(connect.bodyParser());
|
||||
});
|
||||
@@ -266,18 +266,17 @@ module.exports = {
|
||||
app.post('/', function(req, res){
|
||||
res.send(req.param('name') || 'nope');
|
||||
});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', method: 'POST', data: 'name=tj', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }},
|
||||
{ body: 'tj' });
|
||||
},
|
||||
|
||||
|
||||
'test #configure() precedence': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.configure(function(){
|
||||
app.use(function(req, res, next){
|
||||
res.writeHead(200, {});
|
||||
res.write('first');
|
||||
next();
|
||||
});
|
||||
@@ -291,28 +290,28 @@ module.exports = {
|
||||
res.write(' route ');
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'first route last' });
|
||||
},
|
||||
|
||||
|
||||
'test #configure() multiple envs': function(){
|
||||
var app = express.createServer();
|
||||
app.set('env', 'prod');
|
||||
var calls = [];
|
||||
|
||||
|
||||
app.configure('stage', 'prod', function(){
|
||||
calls.push('stage/prod');
|
||||
});
|
||||
|
||||
|
||||
app.configure('prod', function(){
|
||||
calls.push('prod');
|
||||
});
|
||||
|
||||
|
||||
calls.should.eql(['stage/prod', 'prod']);
|
||||
},
|
||||
|
||||
|
||||
'test #set()': function(){
|
||||
var app = express.createServer();
|
||||
var ret = app.set('title', 'My App').set('something', 'else');
|
||||
@@ -320,7 +319,7 @@ module.exports = {
|
||||
app.set('title').should.equal('My App');
|
||||
app.set('something').should.equal('else');
|
||||
},
|
||||
|
||||
|
||||
'test .settings': function(){
|
||||
var app = express.createServer();
|
||||
app.set('title', 'My App');
|
||||
@@ -352,56 +351,67 @@ module.exports = {
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(connect.bodyParser());
|
||||
|
||||
|
||||
assert.equal(2, app.stack.length);
|
||||
|
||||
app.post('/', function(req, res){
|
||||
res.send(JSON.stringify(req.body || ''));
|
||||
});
|
||||
app.get('/', function(){
|
||||
|
||||
|
||||
});
|
||||
assert.equal(3, app.stack.length);
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', method: 'POST', data: 'name=tj', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }},
|
||||
{ body: '{"name":"tj"}' });
|
||||
},
|
||||
|
||||
'test "basepath" setting': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('basepath', '/shop');
|
||||
|
||||
app.get('/redirect', function(req, res){
|
||||
res.redirect('/cart');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/redirect', headers: { Host: 'foo.com' }},
|
||||
{ headers: { Location: 'http://foo.com/shop/cart' }});
|
||||
},
|
||||
|
||||
'test mounting': function(){
|
||||
var called
|
||||
, app = express.createServer()
|
||||
, blog = express.createServer()
|
||||
, map = express.createServer()
|
||||
, reg = connect.createServer();
|
||||
|
||||
map.set('home', '/map');
|
||||
|
||||
map.mounted(function(parent){
|
||||
called = true;
|
||||
assert.equal(this, map, 'mounted() is not in context of the child app');
|
||||
assert.equal(app, parent, 'mounted() was not called with parent app');
|
||||
});
|
||||
|
||||
|
||||
reg.use(function(req, res){ res.end('hey'); });
|
||||
app.use('/regular', reg);
|
||||
|
||||
|
||||
app.use('/blog', blog);
|
||||
app.use('/contact', map);
|
||||
blog.route.should.equal('/blog');
|
||||
map.route.should.equal('/contact');
|
||||
should.equal(true, called);
|
||||
|
||||
|
||||
app.set("test", "parent setting");
|
||||
blog.set('test').should.equal('parent setting');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
app.set('home').should.equal('/');
|
||||
blog.set('home').should.equal('/blog');
|
||||
map.set('home').should.equal('/contact/map');
|
||||
blog.set('basepath').should.equal('/blog');
|
||||
map.set('basepath').should.equal('/contact');
|
||||
res.send('main app');
|
||||
});
|
||||
|
||||
|
||||
blog.get('/', function(req, res){
|
||||
res.send('blog index');
|
||||
});
|
||||
@@ -426,26 +436,26 @@ module.exports = {
|
||||
{ url: '/regular' },
|
||||
{ body: 'hey' });
|
||||
},
|
||||
|
||||
|
||||
'test .app property after returning control to parent': function() {
|
||||
var app = express.createServer()
|
||||
, blog = express.createServer();
|
||||
|
||||
|
||||
// Mounted servers did not restore `req.app` and `res.app` when
|
||||
// passing control back to parent via `out()` in `#handle()`.
|
||||
|
||||
|
||||
blog.get('/', function(req, res, next){
|
||||
req.app.should.equal(blog);
|
||||
res.app.should.equal(blog);
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.use(blog);
|
||||
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
res.send((res.app === app) ? 'restored' : 'not-restored');
|
||||
});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'restored' }
|
||||
@@ -456,23 +466,23 @@ module.exports = {
|
||||
function handle(req, res) {
|
||||
res.send('got ' + req.string);
|
||||
}
|
||||
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
req.string = '/';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
|
||||
app.get('/another', function(req, res, next){
|
||||
req.string = '/another';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'got /' });
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/another' },
|
||||
{ body: 'got /another' });
|
||||
@@ -480,11 +490,11 @@ module.exports = {
|
||||
|
||||
'invalid chars': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send('invalid');
|
||||
});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/%a0' },
|
||||
{ status: 500 });
|
||||
|
||||
2
test/fixtures/magic.jade
vendored
2
test/fixtures/magic.jade
vendored
@@ -3,4 +3,4 @@
|
||||
- else if (lastInCollection)
|
||||
li.last= word
|
||||
- else
|
||||
li(class: 'word-' + indexInCollection)= word
|
||||
li(class='word-' + indexInCollection)= word
|
||||
1
test/fixtures/person.jade
vendored
1
test/fixtures/person.jade
vendored
@@ -1 +0,0 @@
|
||||
p #{label} #{this.name}
|
||||
@@ -3,12 +3,24 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express')
|
||||
var express = require('../')
|
||||
, connect = require('connect')
|
||||
, assert = require('assert')
|
||||
, should = require('should');
|
||||
|
||||
module.exports = {
|
||||
'test #path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/search', function(req, res){
|
||||
res.send(req.path);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/search?q=tobi' },
|
||||
{ body: '/search' });
|
||||
},
|
||||
|
||||
'test #isXMLHttpRequest': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
@@ -155,12 +167,15 @@ module.exports = {
|
||||
req.flash('info').should.eql(['one']);
|
||||
|
||||
req.flash('info', 'Email _sent_.');
|
||||
req.flash('info', '<script>');
|
||||
req.flash('info').should.eql(['Email <em>sent</em>.', '<script>']);
|
||||
req.flash('info', '<em>%s</em>', 'html');
|
||||
req.flash('info').should.eql(['Email <em>sent</em>.', '<em>html</em>']);
|
||||
|
||||
req.flash('info', 'Welcome _%s_ to %s', 'TJ', 'something');
|
||||
req.flash('info').should.eql(['Welcome <em>TJ</em> to something']);
|
||||
|
||||
req.flash('info', 'Welcome %s', '<script>');
|
||||
req.flash('info').should.eql(['Welcome <script>']);
|
||||
|
||||
req.flash('error', 'Foo %u', 'bar');
|
||||
req.flash('error').should.eql(['Foo BAR']);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express')
|
||||
var express = require('../')
|
||||
, Stream = require('stream').Stream
|
||||
, assert = require('assert')
|
||||
, should = require('should');
|
||||
@@ -68,8 +68,8 @@ module.exports = {
|
||||
});
|
||||
|
||||
app.get('/json', function(req, res){
|
||||
res.header('X-Foo', 'bar');
|
||||
res.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
res.header('X-Foo', 'bar')
|
||||
.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
});
|
||||
|
||||
app.get('/text', function(req, res){
|
||||
@@ -97,7 +97,11 @@ module.exports = {
|
||||
app.get('/noargs', function(req, res, next){
|
||||
res.send();
|
||||
});
|
||||
|
||||
|
||||
app.get('/no-content', function(req, res, next){
|
||||
res.send(204);
|
||||
});
|
||||
|
||||
app.get('/undefined', function(req, res, next){
|
||||
res.send(undefined);
|
||||
});
|
||||
@@ -162,6 +166,13 @@ module.exports = {
|
||||
'Content-Type': 'application/octet-stream'
|
||||
, 'Content-Length': '6'
|
||||
}});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/no-content' },
|
||||
{ status: 204 }, function(res){
|
||||
assert.equal(undefined, res.headers['content-type']);
|
||||
assert.equal(undefined, res.headers['content-length']);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/noargs' },
|
||||
@@ -321,13 +332,13 @@ module.exports = {
|
||||
var app = express.createServer()
|
||||
, app2 = express.createServer();
|
||||
|
||||
app2.set('home', '/blog');
|
||||
app2.set('basepath', '/blog');
|
||||
|
||||
app2.redirect('google', 'http://google.com');
|
||||
|
||||
app2.redirect('blog', function(req, res){
|
||||
return req.params.id
|
||||
? '/user/' + req.params.id + '/blog'
|
||||
? '/user/' + req.params.id + '/posts'
|
||||
: null;
|
||||
});
|
||||
|
||||
@@ -368,59 +379,63 @@ module.exports = {
|
||||
res.redirect('blog');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/home', method: 'HEAD' },
|
||||
{ body: '' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/html', headers: { Accept: 'text/html,text/plain', Host: 'foo.com' }},
|
||||
{ body: '<p>Moved Temporarily. Redirecting to <a href="http://google.com">http://google.com</a></p>' });
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Permanently. Redirecting to http://google.com'
|
||||
, status: 301, headers: { Location: 'http://google.com' }});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/back', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/'
|
||||
, status: 302, headers: { Location: 'http://foo.com/', 'Content-Type': 'text/plain' }});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/back', headers: { Referer: '/foo', Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/foo'
|
||||
, status: 302, headers: { Location: 'http://foo.com/foo' }});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/back', headers: { Referrer: '/foo', Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/foo'
|
||||
, status: 302, headers: { Location: 'http://foo.com/foo' }});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/home', headers: { Accept: 'text/plain', Host: 'foo.com' } },
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/'
|
||||
, status: 302, headers: { Location: 'http://foo.com/' }});
|
||||
|
||||
|
||||
assert.response(app2,
|
||||
{ url: '/', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Permanently. Redirecting to http://google.com'
|
||||
, status: 301, headers: { Location: 'http://google.com' }});
|
||||
|
||||
|
||||
assert.response(app2,
|
||||
{ url: '/back', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/blog'
|
||||
, status: 302, headers: { Location: 'http://foo.com/blog' }});
|
||||
|
||||
|
||||
assert.response(app2,
|
||||
{ url: '/home', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/blog'
|
||||
, status: 302, headers: { Location: 'http://foo.com/blog' }});
|
||||
|
||||
|
||||
assert.response(app2,
|
||||
{ url: '/google', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://google.com'
|
||||
, status: 302, headers: { Location: 'http://google.com' }});
|
||||
|
||||
|
||||
assert.response(app2,
|
||||
{ url: '/user/12', headers: { Accept: 'text/plain', Host: 'foo.com' }},
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/user/12/blog'
|
||||
, status: 302, headers: { Location: 'http://foo.com/user/12/blog', 'X-Foo': 'bar' }});
|
||||
{ body: 'Moved Temporarily. Redirecting to http://foo.com/blog/user/12/posts'
|
||||
, status: 302, headers: { Location: 'http://foo.com/blog/user/12/posts', 'X-Foo': 'bar' }});
|
||||
},
|
||||
|
||||
'test #redirect() when mounted': function(){
|
||||
@@ -495,10 +510,6 @@ module.exports = {
|
||||
});
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/forum' },
|
||||
{ body: 'got an error' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/does-not-exist' },
|
||||
{ body: 'got an error' });
|
||||
@@ -656,7 +667,7 @@ module.exports = {
|
||||
'test #cookie() path default': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('home', '/foo');
|
||||
app.set('basepath', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { expires: new Date(1), httpOnly: true });
|
||||
@@ -675,11 +686,11 @@ module.exports = {
|
||||
'test #cookie() explicit path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('/home', '/foo');
|
||||
app.set('/basepath', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { path: '/', expires: new Date(1), httpOnly: true });
|
||||
res.cookie('something', 'else');
|
||||
res.cookie('something', 'else', { path: '/' });
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
@@ -694,7 +705,7 @@ module.exports = {
|
||||
'test #cookie() null path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('/home', '/foo');
|
||||
app.set('/basepath', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.cookie('rememberme', 'yes', { path: null, expires: new Date(1), httpOnly: true });
|
||||
@@ -713,7 +724,7 @@ module.exports = {
|
||||
'test #clearCookie() default path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('home', '/foo');
|
||||
app.set('basepath', '/foo');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.clearCookie('rememberme');
|
||||
@@ -731,7 +742,7 @@ module.exports = {
|
||||
'test #clearCookie() explicit path': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.set('home', '/bar');
|
||||
app.set('basepath', '/bar');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.clearCookie('rememberme', { path: '/foo' });
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express')
|
||||
var express = require('../')
|
||||
, connect = require('connect')
|
||||
, assert = require('assert')
|
||||
, should = require('should')
|
||||
@@ -74,6 +74,245 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test app.param() multiple mapping functions': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.param(function(name, fn){
|
||||
if (fn.length < 3) {
|
||||
return function(req, res, next, val){
|
||||
val = req.params[name] = fn(val);
|
||||
if (false === val) {
|
||||
next('route');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
app.param(function(name, range){
|
||||
if (!~String(range).indexOf('..')) return;
|
||||
var parts = range.split('..')
|
||||
, from = parseInt(parts.shift())
|
||||
, to = parseInt(parts.shift());
|
||||
|
||||
return function(req, res, next, val){
|
||||
if (val < from || val > to) return next('route');
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.param('user', Number);
|
||||
app.param('user', '0..5');
|
||||
|
||||
app.get('/user/:user', function(req, res){
|
||||
res.json(req.params.user);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/3' },
|
||||
{ body: '3' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/6' },
|
||||
{ status: 404 });
|
||||
},
|
||||
|
||||
'test app.param() name passing': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.param(function(name, fn){
|
||||
if (fn.length < 3) {
|
||||
return function(req, res, next, val){
|
||||
val = req.params[name] = fn(val);
|
||||
if (false === val) {
|
||||
next('route');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function within(a, b) {
|
||||
return function(req, res, next, val, name){
|
||||
if (val < a || val > b) {
|
||||
return next(new Error(name + ' should be within ' + a + '..' + b));
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
app.param('user', Number);
|
||||
app.param('user', within(0, 5));
|
||||
|
||||
app.get('/user/:user', function(req, res){
|
||||
res.json(req.params.user);
|
||||
});
|
||||
|
||||
app.use(function(err, req, res, next){
|
||||
res.json({ error: err.message });
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/0' },
|
||||
{ body: '0' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/6' },
|
||||
{ body: '{"error":"user should be within 0..5"}' });
|
||||
},
|
||||
|
||||
'test app.param() multiple callbacks and array of params': function(){
|
||||
var app = express.createServer();
|
||||
var users = [{ name: 'tj' }];
|
||||
var pets = [['tobi', 'loki', 'jane', 'manny', 'luna']];
|
||||
|
||||
function loadUser(req, res, next, id) {
|
||||
req.user = users[id];
|
||||
next();
|
||||
}
|
||||
|
||||
function loadUserPets(req, res, next, id) {
|
||||
req.user.pets = pets[id];
|
||||
next();
|
||||
}
|
||||
|
||||
app.param(['user_id', 'user'], loadUser, loadUserPets);
|
||||
|
||||
app.get('/user/:user_id', function(req, res){
|
||||
res.send(req.user);
|
||||
});
|
||||
|
||||
app.get('/account/:user', function(req, res){
|
||||
res.send(req.user);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/account/0' },
|
||||
{ body: '{"name":"tj","pets":["tobi","loki","jane","manny","luna"]}' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/0' },
|
||||
{ body: '{"name":"tj","pets":["tobi","loki","jane","manny","luna"]}' });
|
||||
},
|
||||
|
||||
'test app.param() multiple callbacks': function(){
|
||||
var app = express.createServer();
|
||||
var users = [{ name: 'tj' }];
|
||||
var pets = [['tobi', 'loki', 'jane', 'manny', 'luna']];
|
||||
|
||||
function loadUser(req, res, next, id) {
|
||||
req.user = users[id];
|
||||
next();
|
||||
}
|
||||
|
||||
function loadUserPets(req, res, next, id) {
|
||||
req.user.pets = pets[id];
|
||||
next();
|
||||
}
|
||||
|
||||
app.param('user_id', loadUser, loadUserPets);
|
||||
|
||||
app.get('/user/:user_id', function(req, res){
|
||||
res.send(req.user);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/0' },
|
||||
{ body: '{"name":"tj","pets":["tobi","loki","jane","manny","luna"]}' });
|
||||
},
|
||||
|
||||
'test app.param() multiple calls with error': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
var commits = ['foo', 'bar', 'baz'];
|
||||
|
||||
app.param('commit', function(req, res, next, id){
|
||||
req.commit = parseInt(id);
|
||||
if (isNaN(req.commit)) return next('route');
|
||||
next();
|
||||
});
|
||||
|
||||
app.param('commit', function(req, res, next, id){
|
||||
req.commit = commits[req.commit];
|
||||
next(new Error('failed'));
|
||||
});
|
||||
|
||||
app.get('/commit/:commit', function(req, res){
|
||||
res.send(req.commit);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/0' },
|
||||
{ status: 500 });
|
||||
},
|
||||
|
||||
'test app.param() multiple calls': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
var commits = ['foo', 'bar', 'baz'];
|
||||
|
||||
app.param('commit', function(req, res, next, id){
|
||||
req.commit = parseInt(id);
|
||||
if (isNaN(req.commit)) return next('route');
|
||||
next();
|
||||
});
|
||||
|
||||
app.param('commit', function(req, res, next, id){
|
||||
req.commit = commits[req.commit];
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/commit/:commit', function(req, res){
|
||||
res.send(req.commit);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/0' },
|
||||
{ body: 'foo' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/0x01' },
|
||||
{ body: 'bar' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/asdf' },
|
||||
{ status: 404 });
|
||||
},
|
||||
|
||||
'test app.param(fn)': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.param(function(name, fn){
|
||||
if (fn instanceof RegExp) {
|
||||
return function(req, res, next, val){
|
||||
var captures;
|
||||
if (captures = fn.exec(String(val))) {
|
||||
req.params[name] = captures[1];
|
||||
next();
|
||||
} else {
|
||||
next('route');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.param('commit', /^(\d+)$/);
|
||||
|
||||
app.get('/commit/:commit', function(req, res){
|
||||
res.send(req.params.commit);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/12' },
|
||||
{ body: '12' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/commit/asdf' },
|
||||
{ status: 404 });
|
||||
},
|
||||
|
||||
'test precedence': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
@@ -138,6 +377,50 @@ module.exports = {
|
||||
{ body: 'Cannot GET /user/ab' });
|
||||
},
|
||||
|
||||
'test named capture group after dot': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/user/:name.:format?', function(req, res){
|
||||
res.send(req.params.name + ' - ' + (req.params.format || ''));
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/foo' },
|
||||
{ body: 'foo - ' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/foo.json' },
|
||||
{ body: 'foo - json' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/foo.bar.json' },
|
||||
{ body: 'foo.bar - json' });
|
||||
},
|
||||
|
||||
'test optional * value': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/admin*', function(req, res){
|
||||
res.send(req.params[0]);
|
||||
});
|
||||
|
||||
app.get('/file/*.*', function(req, res){
|
||||
res.send(req.params[0] + ' - ' + req.params[1]);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/file/some.foo.bar' },
|
||||
{ body: 'some.foo - bar' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/admin', },
|
||||
{ body: '', status: 200 });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/adminify', },
|
||||
{ body: 'ify', status: 200 });
|
||||
},
|
||||
|
||||
'test app.param()': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
@@ -225,7 +508,7 @@ module.exports = {
|
||||
|
||||
var route = app.get('/user/:id')[0]
|
||||
route.should.be.an.instanceof(Route);
|
||||
route.callback.should.be.a('function');
|
||||
route.callbacks.should.be.an.instanceof(Array);
|
||||
route.path.should.equal('/user/:id');
|
||||
route.regexp.should.be.an.instanceof(RegExp);
|
||||
route.method.should.equal('get');
|
||||
@@ -287,7 +570,6 @@ module.exports = {
|
||||
|
||||
var route = app.match.get('/user/12')[0];
|
||||
route.should.be.an.instanceof(Route);
|
||||
route.callback.should.be.a('function');
|
||||
route.path.should.equal('/user/:id');
|
||||
route.regexp.should.be.an.instanceof(RegExp);
|
||||
route.method.should.equal('get');
|
||||
@@ -304,6 +586,17 @@ module.exports = {
|
||||
app.match('/user/123').should.have.length(3);
|
||||
},
|
||||
|
||||
'test app.routes.all()': function(){
|
||||
var app = express.createServer();
|
||||
app.get('/user', function(){});
|
||||
app.get('/user/:id', function(){});
|
||||
app.get('/user/:id/:op?', function(){});
|
||||
app.put('/user/:id', function(){});
|
||||
app.get('/user/:id/edit', function(){});
|
||||
app.routes.all()[0].should.be.an.instanceof(Route);
|
||||
app.routes.all().length.should.equal(5);
|
||||
},
|
||||
|
||||
'test Collection': function(){
|
||||
var app = express.createServer();
|
||||
app.get('/user', function(){});
|
||||
@@ -403,5 +696,130 @@ module.exports = {
|
||||
function(){
|
||||
routes.should.eql(['/:foo?', '/foo']);
|
||||
});
|
||||
},
|
||||
|
||||
'test route callback error handling': function(){
|
||||
var app = express.createServer()
|
||||
, calls = [];
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('one');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('two');
|
||||
next(new Error('fail'));
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('three');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/*', function(err, req, res, next){
|
||||
res.statusCode = 500;
|
||||
res.send('error: ' + err.message);
|
||||
});
|
||||
|
||||
app.get('/user/*', function(req, res, next){
|
||||
calls.push('four');
|
||||
next();
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/12' },
|
||||
{ body: 'error: fail' }, function(){
|
||||
calls.should.eql(['one', 'two']);
|
||||
});
|
||||
},
|
||||
|
||||
'test route callback thrown error handling': function(){
|
||||
var app = express.createServer()
|
||||
, calls = [];
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('one');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('two');
|
||||
throw new Error('fail');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
calls.push('three');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/*', function(err, req, res, next){
|
||||
res.statusCode = 500;
|
||||
res.send('error: ' + err.message);
|
||||
});
|
||||
|
||||
app.get('/user/*', function(req, res, next){
|
||||
calls.push('four');
|
||||
next();
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/12' },
|
||||
{ body: 'error: fail' }, function(){
|
||||
calls.should.eql(['one', 'two']);
|
||||
});
|
||||
},
|
||||
|
||||
'test route callback error recovery': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/user/:id', function(req, res, next){
|
||||
next(new Error('fail'));
|
||||
});
|
||||
|
||||
app.get('/user/*', function(err, req, res, next){
|
||||
req.error = err;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/*', function(req, res, next){
|
||||
res.send('recovered from error: ' + req.error.message);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/user/12' },
|
||||
{ body: 'recovered from error: fail' });
|
||||
},
|
||||
|
||||
'test multiple param callbacks': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.param('user', function(req, res, next, id){
|
||||
req.user = { id: id };
|
||||
next();
|
||||
});
|
||||
|
||||
app.param('forum_id', function(req, res, next, id){
|
||||
req.forum = { id: id };
|
||||
next();
|
||||
});
|
||||
|
||||
app.param('thread_id', function(req, res, next, id){
|
||||
req.thread = { id: id };
|
||||
next();
|
||||
});
|
||||
|
||||
function array(req, res, next) {
|
||||
req.arr = [req.user.id, req.forum.id, req.thread.id];
|
||||
next();
|
||||
}
|
||||
|
||||
app.get('/:user/:forum_id/:thread_id', array, function(req, res){
|
||||
res.send(req.arr);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/1/2/3' },
|
||||
{ body: '["1","2","3"]' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -453,19 +453,6 @@ module.exports = {
|
||||
{ url: '/user' },
|
||||
{ body: '<p>tj</p>' });
|
||||
|
||||
// as: this collection option
|
||||
app.get('/person', function(req, res){
|
||||
res.partial('person.jade', {
|
||||
as: this,
|
||||
collection: [{ name: 'tj' }],
|
||||
locals: { label: 'name:' }
|
||||
});
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/person' },
|
||||
{ body: '<p>name: tj</p>' });
|
||||
|
||||
// as: global collection option
|
||||
app.get('/videos', function(req, res){
|
||||
res.partial('video.jade', {
|
||||
@@ -513,19 +500,6 @@ module.exports = {
|
||||
{ url: '/video-global' },
|
||||
{ body: '<p>Tim Burton</p>' });
|
||||
|
||||
app.get('/person-this', function(req, res){
|
||||
res.partial('person.jade', {
|
||||
object: { name: 'tj' },
|
||||
locals: { label: 'User:' },
|
||||
as: this
|
||||
});
|
||||
});
|
||||
|
||||
// Non-collection as: this
|
||||
assert.response(app,
|
||||
{ url: '/person-this' },
|
||||
{ body: '<p>User: tj</p>' });
|
||||
|
||||
// No options
|
||||
app.get('/nothing', function(req, res){
|
||||
res.partial('hello.ejs');
|
||||
|
||||
Reference in New Issue
Block a user