Skip to content

Commit

Permalink
Supported preset.validator property.
Browse files Browse the repository at this point in the history
  • Loading branch information
bow-fujita committed Feb 2, 2016
1 parent 215e0ff commit afe19b3
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 51 deletions.
119 changes: 108 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![Coverage Status][coveralls-image]][coveralls-url]
[![Dependency Status][david-image]][david-url]
![License][npm-license-image]

Yet another RESTful API framework for [Express](http://expressjs.com/) 4.x.
Expand Down Expand Up @@ -148,9 +149,111 @@ Each element is an object which has the following properties:
+ **`path`: String [Default: `''`]**<br>
Virtual path for this `action`.

+ **`validator`: Object [Default: `undefined`]**<br>
[Validator(s)](#validator) for placeholders in `path`.

+ **`middleware`: {Function|Function[]} [Default: `undefined`]**<br>
[Middleware(s)](#middleware) to be passed to Express.


### `preset` : Object [Default: `undefined`]

The following properties will be applied to each element in `routes`:

+ **`validator`: Object [Default: `undefined`]**<br>
[Validator(s)](#validator) for placeholders in each `path`.

+ **`middleware`: {Function|Function[]} [Default: `undefined`]**<br>
Middleware(s) to be passed to Express.
[Middleware(s)](#middleware) to be passed to Express.


### Validator

If `routes[].path` contains any placeholders to receive parameters from [`req.params`](http://expressjs.com/en/4x/api.html#req.params) object, `validator` will be helpful to validate parameters before calling `routes[].action`.
The following example uses [validator.js](https://github.com/chriso/validator.js) as `validator`:

```javascript
var validator = require('validator')
;

module.exports = {
__exprest: {
routes: [{
action: 'view'
, path: ':id'
, validator: {
id: validator.isNumeric
}
}]
}

, view: function(req, res) {
// `req.params.id` must a number.
res.status(200).json({ id: req.params.id });
}
```
You can also use a `RegExp` object instead of a function as follow:
```javascript
module.exports = {
__exprest: {
routes: [{
action: 'view'
, path: ':id'
, validator: {
id: /^[1-9][0-9]*/
}
}]
}

, view: function(req, res) {
// `req.params.id` must a number.
res.status(200).json({ id: req.params.id });
}
```
If you have a placeholder commonly used in a controller, you can use `preset.validator` as follow:
```javascript
var validator = require('validator')
;

module.exports = {
__exprest: {
preset: {
validator: {
id: validator.isNumeric
}
}
, routes: [
action: 'view'
, path: ':id'
}, {
action: 'update'
, path: ':id'
, method: 'put'
}, {
action: 'remove'
, path: ':id'
, method: 'delete'
}]
}

, view: function(req, res) {
res.status(200).json({ action: 'view', id: req.params.id });
}
, update: function(req, res) {
res.status(200).json({ action: 'update', id: req.params.id });
}
, remove: function(req, res) {
res.status(200).json({ action: 'remove', id: req.params.id });
}
};
```
### Middleware
`middleware` is typically used for APIs accept file uploading.
The following example uses [Multer](https://github.com/expressjs/multer) as `middleware`:
Expand All @@ -176,7 +279,7 @@ module.exports = {
```
Another use case is authentication.
The following example uses [Passport](https://github.com/jaredhanson/passport) as `middleware':
The following example uses [Passport](https://github.com/jaredhanson/passport) as `middleware`:
```javascript
var passport = require('passport')
Expand All @@ -193,18 +296,10 @@ module.exports = {
, login: function(req, res) {
res.status(200).json({ loginAs: req.user.username });
}
};
```
### `preset` : Object [Default: `undefined`]

The following properties will be applied to each element in `__routes`:

+ **`middleware`: {Function|Function[]} [Default: `undefined`]**<br>
Middleware(s) to be passed to Express.

For example, if you want to authenticate users for every action in a controller, you can use `preset.middleware` as follow:
If you want to authenticate users for every action in a controller, you can use `preset.middleware` as follow:
```javascript
var passport = require('passport')
Expand Down Expand Up @@ -257,3 +352,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[travis-url]: https://travis-ci.org/bow-fujita/exprest4
[coveralls-image]: https://img.shields.io/coveralls/bow-fujita/exprest4/master.svg
[coveralls-url]: https://coveralls.io/github/bow-fujita/exprest4?branch=master
[david-image]: https://david-dm.org/bow-fujita/exprest4.svg
[david-url]: https://david-dm.org/bow-fujita/exprest4
53 changes: 35 additions & 18 deletions lib/exprest.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,48 @@ var fs = require('fs')
, util = require('util')
, methods = require('methods')
, _ = require('underscore')
;

var DEFAULT_OPTS = {
, pathToRegExp = require('path-to-regexp')
, DEFAULT_OPTS = {
controllers: path.join(process.cwd(), 'controllers')
, url: '/'
}
;

function buildValidatorChain(validators, handler)
function paramKeys(vpath)
{
var keys = [];
pathToRegExp(vpath, keys);
return _.map(keys, function(key) { return key.name; });
}

function buildValidatorChain(vpath, handler)
{
var keys = paramKeys(vpath);
if (!keys.length) {
return handler;
}

var validators = {};
_.toArray(arguments).slice(2).forEach(function(validator) {
if (_.isObject(validator)) {
_.extend(validators, validator);
}
});

var chain = _.map(validators, function(validator, key) {
var checkFunc;
if (_.isRegExp(validator)) {
checkFunc = function(value) {
return validator.test(value);
};
}
else if (_.isFunction(validator)) {
checkFunc = validator;
var check;
if (~_.indexOf(keys, key)) {
if (_.isRegExp(validator)) {
check = function(value) {
return validator.test(value);
};
}
else if (_.isFunction(validator)) {
check = validator;
}
}

return checkFunc ? { key: key, check: checkFunc } : null;
return check ? { key: key, check: check } : null;
}).filter(function(validator) {
return validator !== null;
})
Expand All @@ -45,10 +65,7 @@ function buildValidatorChain(validators, handler)
return function(req, res, next) {
var ok = _.reduce(chain, function(valid, validator) {
if (valid) {
var value = req.params[validator.key];
if (!_.isUndefined(value)) {
valid = validator.check(value);
}
valid = validator.check(req.params[validator.key]);
}
return valid;
}, true)
Expand Down Expand Up @@ -124,7 +141,7 @@ function load(app, opts, file)
}

var vpath = route.path ? [name, route.path].join('/') : name
, validators = buildValidatorChain(route.validator, handler)
, validators = buildValidatorChain(vpath, handler, preset.validator, route.validator)
, middlewares = buildMiddlewareChain(preset.middleware, route.middleware, validators)
;
app[method](vpath, middlewares);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exprest4",
"version": "0.9.2",
"version": "0.9.3",
"description": "REST API framework for Express 4.x.",
"homepage": "https://github.com/bow-fujita/exprest4",
"repository": {
Expand All @@ -27,6 +27,7 @@
},
"dependencies": {
"methods": "~1.1.2",
"path-to-regexp": "^1.2.1",
"underscore": "~1.8.3"
},
"devDependencies": {
Expand Down
25 changes: 17 additions & 8 deletions test/controllers/routes/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ var validator = require('validator')

module.exports = {
__exprest: {
routes: [{
action: 'id'
, path: 'id/:id'
, validator: {
preset: {
validator: {
id: validator.isNumeric
}
}, {
}
, routes: [{
action: 'email'
, path: 'email/:email'
, validator: {
Expand All @@ -29,16 +28,26 @@ module.exports = {
, validator: {
name: /^[A-Z]+$/i
}
}, {
action: 'preset'
, path: 'preset/:id'
}, {
action: 'preset'
, path: 'overwrite/:id'
, validator: {
id: validator.isAlpha
}
}]
}

, id: function(req, res) {
res.status(200).json({ id: req.params.id });
}
, email: function(req, res) {
res.status(200).json({ email: req.params.email });
}
, regexp: function(req, res) {
res.status(200).json({ name: req.params.name });
}
, preset: function(req, res) {
res.status(200).json({ id: req.params.id });
}

};
38 changes: 25 additions & 13 deletions test/suites/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,6 @@ describe('validators', function() {
done();
});

describe('GET /validator/id', function() {
it('valid', function(done) {
request(app).get('/validator/id/123')
.expect(200, {
id: 123
}, done);
});

it('invalid', function(done) {
request(app).get('/validator/id/abc').expect(404, done);
});
}); // GET /validator/:id

describe('GET /validator/email', function() {
it('valid', function(done) {
request(app).get('/validator/email/user@exprest4.local')
Expand All @@ -62,5 +49,30 @@ describe('validators', function() {
});
}); // GET /validator/regexp

describe('GET /validator/preset', function() {
it('valid', function(done) {
request(app).get('/validator/preset/123')
.expect(200, {
id: 123
}, done);
});

it('invalid', function(done) {
request(app).get('/validator/preset/abc').expect(404, done);
});
}); // GET /validator/preset

describe('GET /validator/overwrite', function() {
it('valid', function(done) {
request(app).get('/validator/overwrite/abc')
.expect(200, {
id: 'abc'
}, done);
});

it('invalid', function(done) {
request(app).get('/validator/overwrite/123').expect(404, done);
});
}); // GET /validator/overwrite

});

0 comments on commit afe19b3

Please sign in to comment.