UNPKG

rest-methods

Version:

Declaratively publish functions for remote invocation.

167 lines (136 loc) 5.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _lodash = require("lodash"); var _lodash2 = _interopRequireDefault(_lodash); var _jsUtil = require("js-util"); var _jsUtil2 = _interopRequireDefault(_jsUtil); var _pageJs = require("../page-js"); var _pageJs2 = _interopRequireDefault(_pageJs); var _errors = require("../errors"); var _MethodDocs = require("./MethodDocs"); var _MethodDocs2 = _interopRequireDefault(_MethodDocs); var _url = require("../url"); /** * Represents a method. */ var ServerMethod = (function () { function ServerMethod(name, func, routePattern, verb, docs) { _classCallCheck(this, ServerMethod); // Setup initial conditions. if (_lodash2["default"].isEmpty(name)) { throw new Error("Method name not specified."); } if (_jsUtil2["default"].isNumeric(name[0])) { throw new Error("Method names cannot start with numbers. Given name: " + name); } if (name.match(/^[a-zA-Z0-9-\/]*$/) === null) { throw new Error("A method name can only contain alpha-numeric characters and '/' or '-'. Given name: " + name); } if (!_lodash2["default"].isFunction(func)) { throw new Error("Function not specified for the method \"" + name + "\"."); } if (_lodash2["default"].isEmpty(routePattern)) { throw new Error("URL pattern not specified for the method \"" + name + "\"."); } if (_lodash2["default"].isEmpty(verb)) { throw new Error("HTTP verb not specified for the method \"" + name + "\"."); } // Store state. this.name = name; this.func = func; this.verb = verb; if (docs) { this.docs = new _MethodDocs2["default"](docs); } // Store routes. this.route = new _pageJs2["default"].Route(routePattern); this.pathRoute = new _pageJs2["default"].Route(routePattern.split("?")[0]); // Route excluding the query-string pattern. var routeKeys = this.route.keys; // Calculate parameters. var params = _jsUtil2["default"].functionParameters(func); if (params.length > 0) { this.params = params.map(function (paramName) { return { name: paramName }; }); } // If the URL route has parameters, ensure the function has enough parameters. if (routeKeys.length > 0 && params.length < routeKeys.length) { var routeParams = routeKeys.map(function (item) { return item.name; }).join(","); throw new Error("The " + verb + " method \"" + name + "\" does not have enough parameters based on the URL route \"" + routePattern + "\". Should be: " + name + "(" + routeParams + ")"); } // Ensure URL params are represented within the function. if (routeKeys.length > 0) { (function () { var index = 0; routeKeys.forEach(function (item) { if (params[index] !== item.name) { throw new Error("The \"" + name + "\" method has a function parameter (\"" + params[index] + "\") at index " + index + " that does not match the URL pattern. URL parameters come first. The parameter should be \"" + item.name + "\"."); } index += 1; }); })(); } } /** * Invokes the method function. * * @param args: An array of arguments. * @param url: The requesting URL. * @return promise. */ _createClass(ServerMethod, [{ key: "invoke", value: function invoke(args, url) { var _this = this; return new Promise(function (resolve, reject) { var rejectWithError = function rejectWithError(err) { err = new _errors.ServerMethodError(err.status, _this.name, args, err.message); reject(err); }; // Extract the URL parameters. var urlParams = (0, _url.getUrlParams)(_this.route, url); // Prepend the URL params to the arguments if there are any. if (urlParams.length > 0) { args = _lodash2["default"].flatten([urlParams, args]); } var thisContext = { verb: _this.verb, url: { path: url, params: urlParams }, "throw": function _throw(status, message) { throw new _errors.ServerMethodError(status, _this.name, args, message); } }; // Attempt to invoke the function. try { var result = _this.func.apply(thisContext, args); if (result && _lodash2["default"].isFunction(result.then)) { // A promise was returned. result.then(function (asyncResult) { resolve(asyncResult); })["catch"](function (err) { rejectWithError(err); }); } else { // A simple value was returned. resolve(result); } } catch (err) { rejectWithError(err); } }); } }]); return ServerMethod; })(); exports["default"] = ServerMethod; module.exports = exports["default"];