Skip to content

Commit

Permalink
Param parsing order is now configurable & added tests for eventual 'u…
Browse files Browse the repository at this point in the history
…se' support
  • Loading branch information
mallocator committed Sep 7, 2016
1 parent d2019ad commit 1f057e6
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 16 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ In addition the router has options specifically for the version mapping:

* param: the parameter name that is used in query and parameter mapping
* header: the header used to look for a requested version
* paramOrder: the order in which parameters are parsed from the client object for all endpoints, the default order is 'params', 'query', 'cookie', 'body', 'header' which map to express properties.
* responseHeader: the name of the header in the response that has information about the matched version. (will be turned off if this is set to falsy)
* passVersion: whether to pass the version on via the request object. this will add two new properties to the request object: incomingVersion and acceptedVersion.

Expand Down Expand Up @@ -129,17 +130,17 @@ Works the same way as the original router method, only now has an optional versi
as the version parameter on the individual methods.


### Router.param
### Router.use
```
router.param(name, [version], callback)
router.use([path], [version], [function, ...] function)
```

Not yet implemented.



### Router.use
### Router.param
```
router.use([path], [version], [function, ...] function)
router.param(name, callback)
```

Not yet implemented.
This is the same as the original method. note that versioning is not supported at this time for the param call.
24 changes: 14 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ var semver = require('semver');
* @property {versionCb} [validate] A validator the overrides the default behavior for checking the version
* @property {string} [param=v] The parameter name used for determining the version
* @property {string} [header=X-ApiVersion] The header name to look for the requested version
* @property {string[]} paramOrder The order in which parameters are parsed from the client object for all endpoints
* The default order is 'params', 'query', 'cookie', 'body' which map to express
* properties. Note that if a header is set it is used instead of any of these.
* @property {string} [responseHeader=X-ApiVersion] The header name to return the resolved version (is a regex|number|string
* depending on what was configured on the endpoint). Will not be used
* if the headers have already been sent before the router gets a chance.
Expand Down Expand Up @@ -42,12 +45,13 @@ var semver = require('semver');
* @type {string[]} The method names npm
*/
var methods = [
'all', 'get', 'post', 'put', 'head', 'delete', 'options', 'trace', 'copy', 'lock', 'mkcol', 'move', 'purge',
'propfind', 'proppatch', 'unlock', 'report', 'mkactivity', 'checkout', 'merge', 'm-search', 'notify',
'all', 'param', 'get', 'post', 'put', 'head', 'delete', 'options', 'trace', 'copy', 'lock', 'mkcol', 'move',
'purge', 'propfind', 'proppatch', 'unlock', 'report', 'mkactivity', 'checkout', 'merge', 'm-search', 'notify',
'subscribe', 'unsubscribe', 'patch', 'search', 'connect'
];

const defaultConfig = {
paramOrder: ['params', 'query', 'cookie', 'body', 'header'],
param: 'v',
header: 'X-ApiVersion',
responseHeader: 'X-ApiVersion',
Expand Down Expand Up @@ -94,10 +98,6 @@ function Router(configuration = {}) {
}));
}
}
let originalParam = router.param;
router.param = (name, version, cb) => {
throw new Error('Not yet implemented');
};
router.use = (path, version, ...handlers) => {
throw new Error('Not yet implemented');
};
Expand Down Expand Up @@ -142,10 +142,14 @@ function generateRouter(endpoint, method) {
* @property {string|number|RegExp} acceptVersion
*/
function parseVersion(req, res, next) {
let version = req.query && req.query[this.configuration.param]
|| req.params && req.params[this.configuration.param]
|| req.cookies && req.cookies[this.configuration.param]
|| req.get(this.configuration.header);
let version = null;
for (let params of this.configuration.paramOrder) {
if (params == 'header') {
version = version || req.get(this.configuration.header);;
} else {
version = version || req[params] && req[params][this.configuration.param];
}
}
let validator = (this.configuration.validate || validateVersion).bind({ req, res });
validator(version, this.acceptVersion, matches => {
if (matches){
Expand Down
67 changes: 67 additions & 0 deletions test/router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,71 @@ describe('Router', () => {
});
});
});

it('should support the param method without a version', done => {
var router = Router();
router.param('variable', (req, res, next, variable) => res.end('success ' + variable));
router.get('/:variable', () => {});

var app = express();
app.use(router);
request(app).get('/test').expect(200, 'success test').end(done);
});

it.skip('should support middleware functions', done => {
var router = Router();
router.use((req, res, next) => next(), (req, res) => res.end('success'));

var app = express();
app.use(router);
request(app).get('/test').expect(200, 'success').end(done);
});

it.skip('should support middleware functions with a path', done => {
var router = Router();
router.use('/test', (req, res, next) => next(), (req, res) => res.end('success'));

var app = express();
app.use(router);
request(app).get('/test').expect(200, 'success').end(done);
});

it.skip('should support middleware functions with a version', done => {
var router = Router();
router.use(1, (req, res, next) => next(), (req, res) => res.end('success 1'));
router.use('^2', (req, res, next) => next(), (req, res) => res.end('success 2'));
router.use(/3/, (req, res, next) => next(), (req, res) => res.end('success 3'));

var app = express();
app.use(router);
request(app).get('/v1/test').expect(200, 'success 1').end(() => {
request(app).get('/test?v=2').expect(200, 'success 2').end(() => {
request(app).get('/test').set('X-ApiVersion', 3).expect(200, 'success 3').end(done);
});
});
});

it.skip('should support middleware functions with a path and version', done => {
var router = Router();
router.use('/test', 1, (req, res, next) => next(), (req, res) => res.end('success 1'));
router.use(/\/test/, 2, (req, res, next) => next(), (req, res) => res.end('success 2'));
router.use('/test', '^3', (req, res, next) => next(), (req, res) => res.end('success 3'));
router.use(/\/test/, '^4', (req, res, next) => next(), (req, res) => res.end('success 4'));
router.use('/test', /5/, (req, res, next) => next(), (req, res) => res.end('success 5'));
router.use(/\/test/, /6/, (req, res, next) => next(), (req, res) => res.end('success 6'));

var app = express();
app.use(router);
request(app).get('/v1/test').expect(200, 'success 1').end(() => {
request(app).get('/test?v=2').expect(200, 'success 2').end(() => {
request(app).get('/test').set('X-ApiVersion', 3).expect(200, 'success 3').end(() => {
request(app).get('/v4/test').expect(200, 'success 4').end(() => {
request(app).get('/test?v=5').expect(200, 'success 5').end(() => {
request(app).get('/test').set('X-ApiVersion', 6).expect(200, 'success 6').end(done);
});
});
});
});
});
});
});

0 comments on commit 1f057e6

Please sign in to comment.