├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── test └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .tern-port 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mario Pareja 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # restify-namespace - simple route namespacing 2 | 3 | Defining sub-routes is something that happens often. Why keep repeating yourself? `restify-namespace` makes it easy to define nested route prefixes to DRY up your routes. 4 | 5 | ## Installation 6 | 7 | npm install --save restify-namespace 8 | 9 | ## Example 10 | 11 | Here is how you might define some routes: 12 | 13 | ```javascript 14 | var namespace = require('restify-namespace'); 15 | var app = restify.createServer(); 16 | namespace(app, '/api', function () { 17 | app.get('/thingys', thingysHandler); 18 | 19 | namespace(app, '/beep', function () { 20 | app.get('/boop', plunkHandler); 21 | }); 22 | }); 23 | ``` 24 | 25 | This would create the following routes: 26 | 27 | GET /api/thingys 28 | GET /api/beep/boop 29 | 30 | ## Not Implemented 31 | 32 | At the moment `restify-namespace` does not support regular expression subroutes. It will throw to warn you of this. 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var methods = [ 2 | 'del', 'get', 'head', 'opts', 'post', 'put', 'patch' 3 | ]; 4 | 5 | module.exports = function (app, prefix, callback) { 6 | var originals = {}; 7 | methods.forEach(function (method) { 8 | var orig = app[method]; 9 | originals[method] = orig; 10 | app[method] = function () { 11 | var args = Array.prototype.slice.call(arguments, 0), 12 | arg = args[0], 13 | regexMsg = 'Regular expression route support is not implemented'; 14 | 15 | if (arg instanceof RegExp) { 16 | throw new Error(regexMsg); 17 | } 18 | 19 | if (typeof arg === 'string') { 20 | args[0] = prefix + arg; 21 | } else if (typeof arg === 'object') { 22 | if (typeof arg.path === 'string') { 23 | arg.path = prefix + arg.path; 24 | } else if (arg.path instanceof RegExp) { 25 | throw new Error(regexMsg); 26 | } 27 | } 28 | orig.apply(this, args); 29 | }; 30 | }); 31 | 32 | callback(); 33 | 34 | methods.forEach(function (method) { 35 | app[method] = originals[method]; 36 | }); 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "restify-namespace", 3 | "version": "0.1.1", 4 | "description": "Namespace your restify routes", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "tape test/*.js && jslint --indent 2 --sloppy -- index.js test/tests.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/mpareja/node-restify-namespace.git" 15 | }, 16 | "keywords": [ 17 | "restify", 18 | "plugin", 19 | "middleware", 20 | "namespace", 21 | "api", 22 | "rest" 23 | ], 24 | "author": "Mario Pareja ", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/mpareja/node-restify-namespace/issues" 28 | }, 29 | "devDependencies": { 30 | "jslint": "^0.7.3", 31 | "restify": "~2.6.0", 32 | "supertest": "~0.8.0", 33 | "tape": "~1.1.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | /*jslint unparam: true */ 2 | var test = require('tape'); 3 | var restify = require('restify'); 4 | var request = require('supertest'); 5 | var namespace = require('..'); 6 | 7 | test('can create a top-level namespace', function (t) { 8 | var app = restify.createServer(); 9 | t.on('end', function () { app.close(); }); 10 | t.plan(1); 11 | 12 | namespace(app, '/beep', function () { 13 | app.get('/boop', function (req, res, next) { 14 | res.json(200, {data: 'boop'}); 15 | next(); 16 | }); 17 | }); 18 | 19 | request(app) 20 | .get('/beep/boop') 21 | .expect(200, {data: 'boop'}) 22 | .end(function (err) { t.error(err); }); 23 | }); 24 | 25 | test('can create multiple levels', function (t) { 26 | var app = restify.createServer(); 27 | t.on('end', function () { app.close(); }); 28 | t.plan(1); 29 | 30 | namespace(app, '/beep', function () { 31 | namespace(app, '/boop', function () { 32 | app.get('/plunk', function (req, res, next) { 33 | res.json(200, {data: 'plunk'}); 34 | next(); 35 | }); 36 | }); 37 | }); 38 | 39 | request(app) 40 | .get('/beep/boop/plunk') 41 | .expect(200, {data: 'plunk'}) 42 | .end(function (err) { t.error(err); }); 43 | }); 44 | 45 | test('can continue adding to top-level after namespace', function (t) { 46 | var app = restify.createServer(); 47 | t.on('end', function () { app.close(); }); 48 | t.plan(1); 49 | 50 | namespace(app, '/beep', function () { return; }); 51 | 52 | app.get('/crunch', function (req, res, next) { 53 | res.json(200, {data: 'crunch'}); 54 | next(); 55 | }); 56 | 57 | request(app) 58 | .get('/crunch') 59 | .expect(200, {data: 'crunch'}) 60 | .end(function (err) { t.error(err); }); 61 | }); 62 | 63 | test('can register name space using options object', function (t) { 64 | var app = restify.createServer(); 65 | t.on('end', function () { app.close(); }); 66 | t.plan(1); 67 | 68 | namespace(app, '/beep', function () { 69 | app.get({ path: '/boop' }, function (req, res, next) { 70 | res.json(200, {data: 'boop'}); 71 | next(); 72 | }); 73 | }); 74 | 75 | request(app) 76 | .get('/beep/boop') 77 | .expect(200, {data: 'boop'}) 78 | .end(function (err) { t.error(err); }); 79 | }); 80 | 81 | test('throws on regex routes', function (t) { 82 | var app = restify.createServer(); 83 | t.plan(2); 84 | 85 | namespace(app, '/beep', function () { 86 | t.throws(function () { 87 | app.get(/\/boop/, function (req, res, next) { 88 | res.json(200, {data: 'boop'}); 89 | next(); 90 | }); 91 | }, /not implemented/); 92 | 93 | t.throws(function () { 94 | app.get({ path: /\/boop/ }, function (req, res, next) { 95 | res.json(200, {data: 'boop'}); 96 | next(); 97 | }); 98 | }, /not implemented/); 99 | }); 100 | }); 101 | --------------------------------------------------------------------------------