diff --git a/lib/middleware/action-validator.js b/lib/middleware/action-validator.js new file mode 100644 index 000000000..5a60163ef --- /dev/null +++ b/lib/middleware/action-validator.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 One Hill Technologies, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +module.exports = function (action) { + return function __blueprint_action_validate (req, res, next) { + Promise.resolve (action.validate (req)) + .then (() => next ()) + .catch (next); + } +}; diff --git a/lib/middleware/index.js b/lib/middleware/index.js index 31ed97c7e..91a4b9270 100644 --- a/lib/middleware/index.js +++ b/lib/middleware/index.js @@ -1,4 +1,21 @@ +/* + * Copyright (c) 2018 One Hill Technologies, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + module.exports = { + actionValidator: require ('./action-validator'), checkPolicy: require ('./check-policy'), executeAction: require ('./execute-action'), handleValidationResult: require ('./handle-validation-result'), diff --git a/lib/router-builder.js b/lib/router-builder.js index 9aed1ee59..7fb7b0af1 100644 --- a/lib/router-builder.js +++ b/lib/router-builder.js @@ -11,6 +11,7 @@ const { forOwn, isFunction, isObjectLike, + isPlainObject, isString, flattenDeep, isArray, @@ -26,7 +27,8 @@ const { handleValidationResult, render, legacySanitizer, - legacyValidator + legacyValidator, + actionValidator } = require ('./middleware'); const { @@ -462,12 +464,10 @@ module.exports = BlueprintObject.extend ({ let result = controllerAction.invoke (params); if (isFunction (result) && (result.length === 2 || result.length === 3)) { - // Let the user know they should migrate the using actions. - console.warn (`*** deprecated: ${action}: Controller actions should return an Action class, not a function`); - // Push the function/array onto the middleware stack. If there is a policy, // then we need to push that before we push the function onto the middleware // stack. + if (opts.policy) middleware.push (this._makePolicyMiddleware (opts.policy)); @@ -476,18 +476,17 @@ module.exports = BlueprintObject.extend ({ else if (isArray (result)) { // Push the function/array onto the middleware stack. If there is a policy, // then we need to push that before any of the functions. - console.warn (`*** deprecated: ${action}: Controller actions should return an Action class, not an array of functions`); if (opts.policy) middleware.push (this._makePolicyMiddleware (opts.policy)); middleware.push (result); } - else if (isObjectLike (result) || result.length === 0) { - if (result.length === 0) + else if (isPlainObject (result) || (result.prototype && result.prototype.execute)) { + let plainObject = !(result.prototype && result.prototype.execute); + + if (!plainObject) result = new result ({controller: controllerAction.obj}); - else - console.warn (`*** deprecated: ${action}: Controller actions should return an Action class, not an object-like action`); // The user elects to have separate validation, sanitize, and execution // section for the controller method. There must be a execution function. @@ -509,31 +508,35 @@ module.exports = BlueprintObject.extend ({ // input data dynamically. We need to check for either one and add middleware // functions if it exists. if (validate || sanitize) { - // The validator can be a f(req) middleware function, an object-like - // schema, or a array of validator middleware functions. if (validate) { - if (isFunction (validate)) { - // We either have an legacy validation function, or a middleware function. - switch (validate.length) { - case 2: - console.warn (`*** deprecated: ${action}: validate function must have the signature f(req,res,next)`); - middleware.push (legacyValidator (validate)); - break; + // The validator can be a f(req) middleware function, an object-like + // schema, or a array of validator middleware functions. - case 3: - middleware.push (validate); - break; - - default: - throw new Error (`Validate function must have the signature f(req,res,next)`); + if (isFunction (validate)) { + if (plainObject) { + switch (validate.length) { + case 2: + middleware.push (legacyValidator (validate)); + break; + + case 3: + // This is a Express middleware function + middleware.push (validate); + break; + } + } + else { + // The validate method is on the action object. We need to pass it + // to the action validator middleware. + middleware.push (actionValidator (result)) } } else if (isArray (validate)) { // We have a middleware function, or an array of middleware functions. middleware.push (validate); } - else if (isObjectLike (validate)) { + else if (isPlainObject (validate)) { console.warn (`*** deprecated: ${action}: Validation schema must be declared on the 'schema' property`); // We have an express-validator schema. @@ -541,7 +544,7 @@ module.exports = BlueprintObject.extend ({ middleware.push (checkSchema (schema)); } else { - throw new Error (`validate must be a f(req, res, next), [...f(req, res, next)], or BlueprintObject-like validation schema [path=${path}]`); + throw new Error (`validate must be a f(req, res, next), [...f(req, res, next)], or object-like validation schema [path=${path}]`); } } diff --git a/tests/dummy/app/controllers/main.js b/tests/dummy/app/controllers/main.js index 83a702d57..e95c9021b 100644 --- a/tests/dummy/app/controllers/main.js +++ b/tests/dummy/app/controllers/main.js @@ -40,6 +40,10 @@ module.exports = Controller.extend ({ performGet () { return Action.extend ({ + validate (req) { + + }, + execute (req, res) { return res.status (200).json (true); }