├── .npmignore ├── .travis.yml ├── .gitignore ├── .editorconfig ├── example └── index.js ├── History.md ├── Makefile ├── package.json ├── index.js ├── README.md └── test └── index.test.js /.npmignore: -------------------------------------------------------------------------------- 1 | benchmark/ 2 | test/ 3 | cov/ 4 | Makefile 5 | covrage.html 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | script: "make test-travis" 5 | after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.log 3 | *.csv 4 | *.dat 5 | *.out 6 | *.pid 7 | *.gz 8 | 9 | coverage.html 10 | coverage/ 11 | cov/ 12 | 13 | package-lock.json 14 | node_modules 15 | 16 | dump.rdb 17 | .DS_Store 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * koa-parameter - example/index.js 3 | * Copyright(c) 2014 dead_horse 4 | * MIT Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | const bodyparser = require('koa-bodyparser'); 14 | const parameter = require('..'); 15 | const Koa = require('koa'); 16 | 17 | const app = new Koa(); 18 | 19 | app.use(bodyparser()); 20 | app.use(parameter(app)); 21 | 22 | app.use(async function (ctx) { 23 | ctx.verifyParams({ 24 | id: 'id', 25 | date: 'date' 26 | }); 27 | ctx.body = 'passed'; 28 | }); 29 | 30 | app.listen(3000); 31 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 3.0.1 / 2017-08-14 3 | ================== 4 | 5 | **fixes** 6 | * [[`66f2e44`](git@github.com:koajs/parameter/commit/66f2e44c7ea217520482d0f37597e6f69b297e80)] - fix: detect method to choose query or body (#11) (haoxin <>) 7 | 8 | 3.0.0 / 2017-07-24 9 | ================== 10 | 11 | * refactor: update to koa@2 (#10) 12 | 13 | 2.1.0 / 2016-07-19 14 | ================== 15 | 16 | * feat: support translate error message (About #8) (#9) 17 | 18 | 2.0.0 / 2015-02-19 19 | ================== 20 | 21 | * update parameter to 1.0.2 22 | 23 | 1.0.0 / 2014-10-15 24 | ================== 25 | 26 | * init koa-parameter middleware 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TESTS = test/*.test.js 2 | REPORTER = tap 3 | TIMEOUT = 3000 4 | MOCHA_OPTS = 5 | 6 | install: 7 | @npm install --registry=https://registry.npmmirror.com 8 | 9 | test: 10 | @NODE_ENV=test ./node_modules/mocha/bin/mocha \ 11 | --reporter $(REPORTER) \ 12 | --timeout $(TIMEOUT) \ 13 | --require should \ 14 | $(MOCHA_OPTS) \ 15 | $(TESTS) 16 | 17 | test-cov: 18 | @NODE_ENV=test node_modules/.bin/istanbul cover \ 19 | ./node_modules/.bin/_mocha \ 20 | -- -u exports \ 21 | --require should \ 22 | $(TESTS) \ 23 | --bail 24 | 25 | test-travis: 26 | @NODE_ENV=test node_modules/.bin/istanbul cover \ 27 | ./node_modules/.bin/_mocha \ 28 | --report lcovonly \ 29 | -- -u exports \ 30 | --require should \ 31 | $(TESTS) \ 32 | --bail 33 | 34 | autod: install 35 | @node_modules/.bin/autod -w --prefix="~"\ 36 | -e example \ 37 | -D mocha,should,istanbul-harmony 38 | @$(MAKE) install 39 | 40 | .PHONY: test 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "koa-parameter", 3 | "version": "3.0.1", 4 | "description": "parameter validate middleware for koa", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "make test" 8 | }, 9 | "keywords": [ 10 | "parameter", 11 | "verify", 12 | "koa", 13 | "middleware" 14 | ], 15 | "files": [ 16 | "index.js" 17 | ], 18 | "author": { 19 | "name": "dead-horse", 20 | "email": "dead_horse@qq.com", 21 | "url": "http://deadhorse.me" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git@github.com:koajs/parameter" 26 | }, 27 | "license": "MIT", 28 | "dependencies": { 29 | "parameter": "^2.2.0" 30 | }, 31 | "devDependencies": { 32 | "autod": "2.4.2", 33 | "istanbul": "^0.4.5", 34 | "koa": "^2.3.0", 35 | "koa-bodyparser": "^4.2.0", 36 | "mocha": "^3.4.2", 37 | "should": "^11.2.1", 38 | "supertest": "^3.0.0" 39 | }, 40 | "engine": { 41 | "node": ">=7.6" 42 | } 43 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * koa-parameter - index.js 3 | * Copyright(c) 2014 dead_horse 4 | * MIT Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | const Parameter = require('parameter'); 14 | 15 | module.exports = function (app, translate) { 16 | let parameter; 17 | 18 | if (typeof translate === 'function') { 19 | parameter = new Parameter({ 20 | translate 21 | }) 22 | } else { 23 | parameter = new Parameter() 24 | } 25 | 26 | app.context.verifyParams = function(rules, params) { 27 | if (!rules) { 28 | return; 29 | } 30 | 31 | if (!params) { 32 | params = ['GET', 'HEAD'].includes(this.method.toUpperCase()) 33 | ? this.request.query 34 | : this.request.body; 35 | 36 | // copy 37 | params = Object.assign({}, params, this.params); 38 | } 39 | const errors = parameter.validate(rules, params); 40 | if (!errors) { 41 | return; 42 | } 43 | this.throw(422, 'Validation Failed', { 44 | code: 'INVALID_PARAM', 45 | errors: errors, 46 | params: params 47 | }); 48 | }; 49 | 50 | return async function verifyParam(ctx, next) { 51 | try { 52 | await next(); 53 | } catch (err) { 54 | if (err.code === 'INVALID_PARAM') { 55 | ctx.status = 422; 56 | ctx.body = { 57 | message: err.message, 58 | errors: err.errors, 59 | params: err.params 60 | }; 61 | return; 62 | } 63 | throw err; 64 | } 65 | }; 66 | }; 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | koa-parameter 2 | --------------- 3 | 4 | [![NPM version][npm-image]][npm-url] 5 | [![build status][travis-image]][travis-url] 6 | [![Test coverage][coveralls-image]][coveralls-url] 7 | [![David deps][david-image]][david-url] 8 | [![node version][node-image]][node-url] 9 | [![Gittip][gittip-image]][gittip-url] 10 | 11 | [npm-image]: https://img.shields.io/npm/v/koa-parameter.svg?style=flat-square 12 | [npm-url]: https://npmjs.org/package/koa-parameter 13 | [travis-image]: https://img.shields.io/travis/koajs/parameter.svg?style=flat-square 14 | [travis-url]: https://travis-ci.org/koajs/parameter 15 | [coveralls-image]: https://img.shields.io/coveralls/koajs/parameter.svg?style=flat-square 16 | [coveralls-url]: https://coveralls.io/r/koajs/parameter?branch=master 17 | [david-image]: https://img.shields.io/david/koajs/parameter.svg?style=flat-square 18 | [david-url]: https://david-dm.org/koajs/parameter 19 | [node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square 20 | [node-url]: http://nodejs.org/download/ 21 | [gittip-image]: https://img.shields.io/gittip/dead-horse.svg?style=flat-square 22 | [gittip-url]: https://www.gittip.com/dead-horse/ 23 | 24 | parameter validate middleware for koa, powered by [parameter](https://github.com/node-modules/parameter). 25 | 26 | ## Installation 27 | 28 | ```bash 29 | $ npm install koa-parameter --save 30 | ``` 31 | 32 | ## Usage 33 | 34 | ```js 35 | const Koa = require('koa'); 36 | const parameter = require('koa-parameter'); 37 | 38 | const app = new Koa(); 39 | 40 | parameter(app); // add verifyParams method, but don't add middleware to catch the error 41 | // app.use(parameter(app)); // also add a middleware to catch the error. 42 | 43 | app.use(async function (ctx) { 44 | ctx.verifyParams({ 45 | name: 'string' 46 | }); 47 | }); 48 | ``` 49 | 50 | Checkout [parameter](https://github.com/node-modules/parameter) to get all the rules. 51 | 52 | ## Translate 53 | 54 | You can override the translate method of parameter to implement I18n, by passing a function like this : 55 | 56 | ```js 57 | const Koa = require('koa'); 58 | const parameter = require('koa-parameter'); 59 | 60 | const app = new Koa(); 61 | 62 | parameter(app, function() { 63 | // Same example with node-parameter 64 | var args = Array.prototype.slice.call(arguments); 65 | // Assume there have I18n.t method for convert language. 66 | return I18n.t.apply(I18n, args); 67 | }); 68 | 69 | app.use(async function (ctx) { 70 | ctx.verifyParams({ 71 | name: 'string' 72 | }); 73 | }); 74 | ``` 75 | 76 | ## [Example](example/index.js) 77 | 78 | ### License 79 | 80 | MIT 81 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * koa-parameter - test/index.test.js 3 | * Copyright(c) 2014 dead_horse 4 | * MIT Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | */ 12 | 13 | const util = require('util'); 14 | const bodyparser = require('koa-bodyparser'); 15 | const request = require('supertest'); 16 | const parameter = require('..'); 17 | const Koa = require('koa'); 18 | 19 | describe('koa-paramter', function () { 20 | it('should verify query ok', function (done) { 21 | const app = new Koa(); 22 | app.use(bodyparser()); 23 | app.use(parameter(app)); 24 | app.use(async function (ctx) { 25 | ctx.verifyParams({ 26 | id: 'id', 27 | name: 'string' 28 | }); 29 | ctx.body = 'passed'; 30 | }); 31 | 32 | request(app.listen()) 33 | .get('/?id=1&name=foo') 34 | .expect(200) 35 | .expect('passed', done); 36 | }); 37 | 38 | it('should verify query error', function (done) { 39 | const app = new Koa(); 40 | app.use(parameter(app)); 41 | app.use(bodyparser()); 42 | app.use(async function (ctx) { 43 | ctx.verifyParams({ 44 | id: 'id', 45 | name: 'string' 46 | }); 47 | ctx.body = 'passed'; 48 | }); 49 | 50 | request(app.listen()) 51 | .get('/?id=x&name=foo') 52 | .expect(422) 53 | .expect({ 54 | message: 'Validation Failed', 55 | errors: [{ 56 | field: 'id', 57 | message: 'should match /^\\d+$/', 58 | code: 'invalid' 59 | }], 60 | params: { id: 'x', name: 'foo' } 61 | }, done); 62 | }); 63 | 64 | it('should verify body ok', function (done) { 65 | const app = new Koa(); 66 | app.use(bodyparser()); 67 | app.use(parameter(app)); 68 | app.use(async function (ctx) { 69 | ctx.verifyParams({ 70 | id: 'id', 71 | name: 'string' 72 | }); 73 | ctx.body = 'passed'; 74 | }); 75 | 76 | request(app.listen()) 77 | .post('/?id=1&name=foo') 78 | .send({ 79 | id: '1', 80 | name: 'foo' 81 | }) 82 | .expect(200) 83 | .expect('passed', done); 84 | }); 85 | 86 | it('should verify body error', function (done) { 87 | const app = new Koa(); 88 | app.use(bodyparser()); 89 | app.use(parameter(app)); 90 | app.use(async function (ctx) { 91 | ctx.verifyParams({ 92 | id: 'id', 93 | name: 'string' 94 | }); 95 | ctx.body = 'passed'; 96 | }); 97 | 98 | request(app.listen()) 99 | .post('/?id=x&name=foo') 100 | .send({ 101 | id: 'xx', 102 | name: 'foo' 103 | }) 104 | .expect(422) 105 | .expect({ 106 | message: 'Validation Failed', 107 | errors: [{ 108 | field: 'id', 109 | message: 'should match /^\\d+$/', 110 | code: 'invalid' 111 | }], 112 | params: { id: 'xx', name: 'foo' } 113 | }, done); 114 | }); 115 | 116 | it('should ignore other error', function (done) { 117 | const app = new Koa(); 118 | app.use(bodyparser()); 119 | app.use(parameter(app)); 120 | app.use(async function (ctx) { 121 | ctx.verifyParams({ 122 | id: 'id', 123 | name: 'string' 124 | }); 125 | ctx.body = 'passed'; 126 | ctx.throw('throw error'); 127 | }); 128 | 129 | request(app.listen()) 130 | .post('/?id=1&name=foo') 131 | .send({ 132 | id: '1', 133 | name: 'foo' 134 | }) 135 | .expect(500) 136 | .expect('Internal Server Error', done); 137 | }); 138 | 139 | it('should ignore without rule', function (done) { 140 | const app = new Koa(); 141 | app.use(bodyparser()); 142 | app.use(parameter(app)); 143 | app.use(async function (ctx) { 144 | ctx.verifyParams(); 145 | ctx.body = 'passed'; 146 | }); 147 | 148 | request(app.listen()) 149 | .post('/?id=1&name=foo') 150 | .send({ 151 | id: '1', 152 | name: 'foo' 153 | }) 154 | .expect(200) 155 | .expect('passed', done); 156 | }); 157 | 158 | it('should not add middleware', function (done) { 159 | const app = new Koa(); 160 | parameter(app); 161 | app.use(async function (ctx) { 162 | ctx.verifyParams({ 163 | id: 'id', 164 | name: 'string' 165 | }); 166 | ctx.body = 'passed'; 167 | }); 168 | 169 | request(app.listen()) 170 | .get('/?id=x&name=foo') 171 | .expect(422) 172 | .expect('Validation Failed', done); 173 | }); 174 | 175 | it('should verify input params', function (done) { 176 | const app = new Koa(); 177 | parameter(app); 178 | app.use(async function (ctx) { 179 | const params = { 180 | id: 'x', 181 | name: 'foo' 182 | }; 183 | const rule = { 184 | id: 'id', 185 | name: 'string' 186 | }; 187 | 188 | ctx.verifyParams(rule, params); 189 | ctx.body = 'passed'; 190 | }); 191 | 192 | request(app.listen()) 193 | .get('/') 194 | .expect(422) 195 | .expect('Validation Failed', done); 196 | }); 197 | 198 | it('should translate error message', function (done) { 199 | const app = new Koa(); 200 | app.use(parameter(app, function() { 201 | var args = Array.prototype.slice.call(arguments); 202 | args[0] = args[0].replace('should match %s', 'doit correspondre à %s'); 203 | return util.format.apply(util, args); 204 | })); 205 | app.use(async function (ctx) { 206 | const params = { 207 | id: 'hi im not an id', 208 | }; 209 | const rule = { 210 | id: 'id' 211 | }; 212 | 213 | ctx.verifyParams(rule, params); 214 | ctx.body = 'passed'; 215 | }); 216 | 217 | request(app.listen()) 218 | .get('/') 219 | .expect(422) 220 | .expect({ 221 | message: 'Validation Failed', 222 | errors: [{ 223 | field: 'id', 224 | message: 'doit correspondre à /^\\d+$/', 225 | code: 'invalid' 226 | }], 227 | params: { id: 'hi im not an id' } 228 | }, done); 229 | }); 230 | }); 231 | --------------------------------------------------------------------------------