diff --git a/Makefile b/Makefile index e9595ad..76f3eba 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ test: @./node_modules/.bin/mocha --require should --compilers coffee:coffee-script $(TESTS) test-docs: - @./node_modules/.bin/mocha --reporter doc --require should --compilers coffee:coffee-script $(TESTS) > tests.html + @./node_modules/.bin/mocha --reporter markdown --require should --compilers coffee:coffee-script $(TESTS) > doc.html compile: @./node_modules/.bin/coffee -o lib src diff --git a/README.mkd b/README.mkd new file mode 100644 index 0000000..89c5437 --- /dev/null +++ b/README.mkd @@ -0,0 +1,75 @@ +## flask-router + + Routing system for node.js/connect based on Flask(http://flask.pocoo.org/). + +#### Usage + +```js +var connect = require('connect') + , app = connect() + , router = require('flask-router')(); + +app.use(router.route); + +router.get('/users/', function (req, res) { + console.log(req.params.id); + res.end(); +}); + +router.post('/users/', function (req, res) { + console.log(req.params.id); + res.end(); +}); + +router.put('/customers/', function (req, res) { + console.log(req.params.id); + res.end(); +}); +``` + + Can assign multiple handler functions to the same rule: + +```js +router.get('/pattern/that/uses/many/handlers' +, function(req, res, next) { + res.write('part1'); + return next(); +}, function(req, res, next) { + res.write('part2'); + return next(); +}); + +router.get('/pattern/that/uses/many/handlers', function(req, res) { + res.write('part3'); + return res.end(); +}); +// All three handlers will be executed when the url match, so the final +// response will be 'part1part2part3' +``` + + Custom parameter parsers can be registered(these are known as 'converters' + in Flask/Werkzeug): + +```js +router.registerParser('options', function(str) { + var rv = {}; + , options = str.split('/') + , i, len, kv, key, value; + for (i = 0, len = options.length; i < len; i++) { + option = options[i]; + kv = option.split('='); + key = kv[0], value = kv[1]; + rv[key] = value; + } + return rv; +}); + +router.get('/queryable/', function(req, res) { + console.log(JSON.stringify(req.params.query)); + res.end(); +}); +// If '/queryable/gt=5/lt=10/limit=20' was requested, +// the output would be {"limit":"20","gt":"5","lt":"10"} +``` + + See tests for more examples. diff --git a/package.json b/package.json index 8679b98..a6707a7 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "flask-router", "version": "0.0.1", "description": "Flask-inspired routing system for node and connect.\nNice if you just need a routing system without depending on connect, or need routing middleware without all features provided by express.", + "main": "./lib/router.js", "repository": { "type": "git", "url": "" @@ -20,6 +21,7 @@ "license": "BSD", "devDependencies": { "coffee-script": "1.3.3", + "connect": "*", "should": "*", "mocha": "*" }, diff --git a/src/router.coffee b/src/router.coffee index 7f2bbba..0f9087d 100644 --- a/src/router.coffee +++ b/src/router.coffee @@ -314,6 +314,7 @@ module.exports = (parsers) -> return { route: (req, res, next) -> r.route(req, res, next) + registerParser: (name, parser) -> compiler.parsers[name] = parser get: (pattern, handlers...) -> r.register('GET', pattern, handlers...) post: (pattern, handlers...) -> r.register('POST', pattern, handlers...) put: (pattern, handlers...) -> r.register('PUT', pattern, handlers...) diff --git a/test/router.coffee b/test/router.coffee index 3ce8379..5387dba 100644 --- a/test/router.coffee +++ b/test/router.coffee @@ -6,26 +6,27 @@ describe 'Rules', -> app = connect() app.use(router.route) - router.get '/$imple/.get/pattern$', (req, res) -> - res.write('body1') - res.end() + before -> + router.get '/$imple/.get/pattern$', (req, res) -> + res.write('body1') + res.end() - router.post('/not-a-get/pattern*', -> res.end()) + router.post('/not-a-get/pattern*', -> res.end()) - router.del('/not-a-get/pattern*', -> res.end()) + router.del('/not-a-get/pattern*', -> res.end()) - router.get '/^pattern/that/uses/many/handlers', - (req, res, next) -> res.write('part1'); next(), - (req, res, next) -> res.write('part2'); next() + router.get '/^pattern/that/uses/many/handlers', + (req, res, next) -> res.write('part1'); next(), + (req, res, next) -> res.write('part2'); next() - router.get '/^pattern/that/uses/many/handlers', - (req, res) -> res.write('part3'); res.end() + router.get '/^pattern/that/uses/many/handlers', + (req, res) -> res.write('part3'); res.end() - router.get '/cancel', - (req, res, next) -> res.write('p1'); next(), - (req, res, next) -> res.write('p2'); res.end(), - (req, res, next) -> res.write('p3'); next(), - (req, res, next) -> res.write('p4'); res.end() + router.get '/cancel', + (req, res, next) -> res.write('p1'); next(), + (req, res, next) -> res.write('p2'); res.end(), + (req, res, next) -> res.write('p3'); next(), + (req, res, next) -> res.write('p4'); res.end() it 'should match simple patterns', (done) -> app.request() @@ -33,6 +34,7 @@ describe 'Rules', -> .end (res) -> res.body.should.eql('body1') done() + return it "should return 405 when pattern doesn't match method", (done) -> app.request() @@ -285,18 +287,18 @@ describe 'Multiple parameters', -> describe 'Custom parser', -> - router = createRouter - options: (str) -> - rv = {} - options = str.split('/') - for option in options - [key, value] = option.split('=') - rv[key] = value - return rv - + router = createRouter() app = connect() app.use(router.route) + router.registerParser 'options', (str) -> + rv = {} + options = str.split('/') + for option in options + [key, value] = option.split('=') + rv[key] = value + return rv + router.get '/transactions/', (req, res) -> res.write(JSON.stringify(req.params.query)) res.end() @@ -305,6 +307,7 @@ describe 'Custom parser', -> app.request() .get('/transactions/gt=5/lt=10/limit=20') .end (res) -> + console.log(res.body) JSON.parse(res.body).should.eql gt: '5' lt: '10'