diff --git a/History.md b/History.md index 5665ad3..c734bda 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,7 @@ +7.0.0 / 2019-10-08 +================== + + * deps; [semver-major] bump @hapi/joi from 15.x -> 16.x 6.0.0 / 2019-04-27 ================== diff --git a/output-validation-rule.js b/output-validation-rule.js index 739a191..4e9a09f 100644 --- a/output-validation-rule.js +++ b/output-validation-rule.js @@ -1,7 +1,6 @@ 'use strict'; const assert = require('assert'); -const Joi = require('@hapi/joi'); const helpMsg = ' -> see: https://github.com/koajs/joi-router/#validating-output'; module.exports = OutputValidationRule; @@ -66,18 +65,20 @@ OutputValidationRule.prototype.matches = function matches(ctx) { * Validates this rule against the given `ctx`. */ -OutputValidationRule.prototype.validateOutput = function validateOutput(ctx) { +OutputValidationRule.prototype.validateOutput = function validateOutput(ctx, validatorBuilder) { let result; if (this.spec.headers) { - result = Joi.validate(ctx.response.headers, this.spec.headers); + const validator = validatorBuilder(this.spec.headers) + result = validator(ctx.response.headers); if (result.error) return result.error; // use casted values ctx.set(result.value); } if (this.spec.body) { - result = Joi.validate(ctx.body, this.spec.body); + const validator = validatorBuilder(this.spec.body) + result = validator(ctx.body); if (result.error) return result.error; // use casted values ctx.body = result.value; diff --git a/output-validator.js b/output-validator.js index 6e65620..a118bc3 100644 --- a/output-validator.js +++ b/output-validator.js @@ -39,13 +39,13 @@ function assertNoOverlappingStatusRules(rules) { } }; -OutputValidator.prototype.validate = function(ctx) { +OutputValidator.prototype.validate = function(ctx, validatorBuilder) { assert(ctx, 'missing request context!'); for (let i = 0; i < this.rules.length; ++i) { const rule = this.rules[i]; if (rule.matches(ctx)) { - return rule.validateOutput(ctx); + return rule.validateOutput(ctx, validatorBuilder); } } }; diff --git a/package.json b/package.json index 5025210..f5d35a2 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "koa-joi-router", - "version": "6.0.0", + "name": "koa-not-so-joi-router", + "version": "7.1.0", "description": "Configurable, input validated routing for koa.", - "main": "joi-router.js", + "main": "router.js", "keywords": [ "joi", "koa", @@ -26,14 +26,13 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/koajs/joi-router.git" + "url": "https://github.com/janzal/not-so-joi-router.git" }, "bugs": { - "url": "https://github.com/koajs/joi-router/issues" + "url": "https://github.com/janzal/not-so-joi-router/issues" }, - "homepage": "https://github.com/koajs/joi-router", + "homepage": "https://github.com/janzal/not-so-joi-router", "dependencies": { - "@hapi/joi": "15.0.0", "await-busboy": "1.0.3", "clone": "2.1.2", "co-body": "6.0.0", @@ -46,6 +45,7 @@ "sliced": "1.0.1" }, "devDependencies": { + "@hapi/joi": "^16.1.7", "eslint": "^5", "koa": "^2.1", "mocha": "^6.0.2", diff --git a/joi-router.js b/router.js similarity index 95% rename from joi-router.js rename to router.js index 0fc1bee..b4e65fa 100644 --- a/joi-router.js +++ b/router.js @@ -8,7 +8,6 @@ const methods = require('methods'); const KoaRouter = require('koa-router'); const busboy = require('await-busboy'); const parse = require('co-body'); -const Joi = require('@hapi/joi'); const slice = require('sliced'); const delegate = require('delegates'); const clone = require('clone'); @@ -16,16 +15,22 @@ const OutputValidator = require('./output-validator'); module.exports = Router; -// expose Joi for use in applications -Router.Joi = Joi; +function identity(obj) { + return obj; +} -function Router() { +function Router({ + validatorBuilder +} = { validatorBuilder: identity }) { if (!(this instanceof Router)) { - return new Router(); + return new Router({ + validatorBuilder + }); } this.routes = []; this.router = new KoaRouter(); + this.validatorBuilder = validatorBuilder } /** @@ -116,7 +121,7 @@ Router.prototype._addRoute = function addRoute(spec) { const bodyParser = makeBodyParser(spec); const specExposer = makeSpecExposer(spec); - const validator = makeValidator(spec); + const validator = makeValidator(spec, this.validatorBuilder); const preHandlers = spec.pre ? flatten(spec.pre) : []; const handlers = flatten(spec.handler); @@ -400,7 +405,7 @@ function captureError(ctx, type, err) { * @api private */ -function makeValidator(spec) { +function makeValidator(spec, validatorBuilder) { const props = 'header query params body'.split(' '); return async function validator(ctx, next) { @@ -412,7 +417,7 @@ function makeValidator(spec) { const prop = props[i]; if (spec.validate[prop]) { - err = validateInput(prop, ctx, spec.validate); + err = validateInput(prop, ctx, spec.validate, validatorBuilder); if (err) { captureError(ctx, prop, err); @@ -426,7 +431,7 @@ function makeValidator(spec) { if (spec.validate._outputValidator) { debug('validating output'); - err = spec.validate._outputValidator.validate(ctx); + err = spec.validate._outputValidator.validate(ctx, validatorBuilder); if (err) { err.status = 500; return ctx.throw(err); @@ -470,11 +475,12 @@ async function prepareRequest(ctx, next) { * @api private */ -function validateInput(prop, ctx, validate) { +function validateInput(prop, ctx, validate, validatorBuilder) { debug('validating %s', prop); const request = ctx.request; - const res = Joi.validate(request[prop], validate[prop]); + const validator = validatorBuilder(validate[prop]); + const res = validator(request[prop]); if (res.error) { res.error.status = validate.failure; diff --git a/test/index.js b/test/index.js index a4d3247..311bcaa 100644 --- a/test/index.js +++ b/test/index.js @@ -1,6 +1,6 @@ 'use strict'; -const router = require('../'); +const routerFactory = require('../'); const Koa = require('koa'); const assert = require('assert'); const request = require('supertest'); @@ -10,6 +10,19 @@ const methods = require('methods'); const slice = require('sliced'); const MiddlewareGenerator = require('./test-utils').MiddlewareGenerator; +function joiValidatorBuilder(schema) { + const validator = Joi.compile(schema); + return (obj) => { + return validator.validate(obj) + } +} + +const router = () => { + return routerFactory({ + validatorBuilder: joiValidatorBuilder + }) +} + function makeRouterApp(router) { const app = new Koa(); app.use(router.middleware()); @@ -20,7 +33,7 @@ function test(app) { return request(http.createServer(app.callback())); } -describe('koa-joi-router', () => { +describe('koa-not-so-joi-router', () => { it('exposes a function', (done) => { assert.equal('function', typeof router); done(); @@ -28,12 +41,7 @@ describe('koa-joi-router', () => { it('is a constructor', (done) => { const r = router(); - assert(r instanceof router); - done(); - }); - - it('exposes the Joi module', (done) => { - assert.equal(router.Joi, Joi); + assert(r instanceof routerFactory); done(); }); @@ -182,7 +190,6 @@ describe('koa-joi-router', () => { return next(); }, handler: (ctx) => { - console.log('ctx.request.body', ctx.request.body); ctx.body = ctx.request.body; } });