diff --git a/docs/Reference.md b/docs/Reference.md index 42614be3b..e8eaf5369 100755 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -538,6 +538,7 @@ The following options are available when adding a route: - `failAction` - defines what to do when a response fails validation. Options are: - `error` - return an Internal Server Error (500) error response. This is the default value. - `log` - log the error but send the response. + - `modify` - if `true`, applies the validation rule changes to the response. Defaults to `false`. - `cache` - if the route method is 'GET', the route can be configured to include caching directives in the response using the following options: - `privacy` - determines the privacy flag included in client-side caching using the 'Cache-Control' header. Values are: diff --git a/lib/schema.js b/lib/schema.js index 7b2ef6e6f..fded9889f 100755 --- a/lib/schema.js +++ b/lib/schema.js @@ -221,8 +221,10 @@ internals.routeConfig = Joi.object({ response: Joi.object({ schema: Joi.alternatives(Joi.object(), Joi.func()).allow(true, false).required(), sample: Joi.number().min(0).max(100), - failAction: Joi.string().valid('error', 'log') - }), + failAction: Joi.string().valid('error', 'log'), + modify: Joi.boolean() + }) + .without('modify', 'sample'), cache: Joi.object({ privacy: Joi.string().valid('default', 'public', 'private'), expiresIn: Joi.number(), diff --git a/lib/validation.js b/lib/validation.js index b66c8a19e..4062471b7 100755 --- a/lib/validation.js +++ b/lib/validation.js @@ -137,6 +137,12 @@ exports.response = function (request, next) { var postValidate = function (err, value) { if (!err) { + if (value !== undefined && + request.route.response.modify) { + + request.response.source = value; + } + return next(); } diff --git a/test/validation.js b/test/validation.js index 2a9644a8e..370cd9cdb 100755 --- a/test/validation.js +++ b/test/validation.js @@ -614,6 +614,66 @@ describe('Validation', function () { }); }); + it('validates and modifies response', function (done) { + + var handler = function (request, reply) { + + return reply({ a: 1, b: 2 }); + }; + + var server = new Hapi.Server({ debug: false }); + server.connection(); + server.route({ + method: 'GET', + path: '/', + config: { + response: { + schema: Joi.object({ + a: Joi.number() + }).options({ stripUnknown: true }), + modify: true + } + }, + handler: handler + }); + + server.inject('/', function (res) { + + expect(res.statusCode).to.equal(200); + expect(res.result).to.deep.equal({ a: 1 }); + done(); + }); + }); + + it('throws on sample with response modify', function (done) { + + var handler = function (request, reply) { + + return reply({ a: 1, b: 2 }); + }; + + var server = new Hapi.Server({ debug: false }); + server.connection(); + expect(function () { + + server.route({ + method: 'GET', + path: '/', + config: { + response: { + schema: Joi.object({ + a: Joi.number() + }).options({ stripUnknown: true }), + modify: true, + sample: 90 + } + }, + handler: handler + }); + }).to.throw(/modify conflict with forbidden peer sample/); + done(); + }); + it('validates response using custom validation function', function (done) { var i = 0;