rest-methods
Version:
Declaratively publish functions for remote invocation.
249 lines (205 loc) • 8.16 kB
JavaScript
;
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 _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj["default"] = obj; return newObj; } }
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 _ClientMethod = require("./ClientMethod");
var _ClientMethod2 = _interopRequireDefault(_ClientMethod);
var _jsUtil = require("js-util");
var util = _interopRequireWildcard(_jsUtil);
var _httpPromisesBrowser = require("http-promises/browser");
var _httpPromisesBrowser2 = _interopRequireDefault(_httpPromisesBrowser);
var _const = require("../const");
var STATE = Symbol("state");
exports.STATE = STATE;
var isBrowser = typeof window !== "undefined" && window !== null;
/**
* Initalizes the proxy with the server methods.
* @param {Client} client: The Client proxy to the server.
* @param {object} methodsManifest: An object containing the method definitions from the server.
* NB: The the [methods] object form the manifest.
*/
var registerMethods = function registerMethods(client) {
var methodsManifest = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var _client$STATE = client[STATE];
var host = _client$STATE.host;
var http = _client$STATE.http;
// Store methods.
_lodash2["default"].keys(methodsManifest).forEach(function (key) {
var options = methodsManifest[key];
options.host = host;
var method = new _ClientMethod2["default"](key, http, options);
client[STATE].methods[key] = method;
// Create proxy-stubs to the method.
var stub = util.ns(client.methods, key, { delimiter: "/" });
_lodash2["default"].keys(method.verbs).forEach(function (verb) {
stub[verb] = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return method.invoke(verb, args);
};
});
});
// Invoke ready handlers.
client.isReady = true;
client[STATE].readyHandlers.invoke();
client[STATE].readyHandlers = new _jsUtil.Handlers(); // Reset.
};
exports.registerMethods = registerMethods;
/**
* The client proxy to server methods.
*/
var Client = (function () {
/**
* Constructor.
* Initializes the module client-side, pulling the
* manifest of methods from the server.
* @param options
* - http: The HTTP object to use for making requests.
* - host: The host-name of the remote server,
* For example:
* - http://domain.com
* - localhost:3030
*/
function Client() {
var _this = this;
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
_classCallCheck(this, Client);
// Private field: HTTP.
var http = options.http;
if (isBrowser && !http) {
http = _httpPromisesBrowser2["default"];
}
if (!http) {
throw new Error("An [http] gateway was not given to the [Client].");
}
// Private field: Host.
var host = options.host;
if (!isBrowser && !host) {
throw new Error("A [host] name must be given when connecting a server to a remove server (eg. https://domain.com, or localhost:3030) ");
}
if (host) {
if (!_lodash2["default"].startsWith(host, "http")) {
host = "http://" + host;
}
host = host.replace(/\/*$/, "");
}
// Private field: State.
this[STATE] = {
methods: {},
readyHandlers: new _jsUtil.Handlers(),
http: http,
host: host
};
/**
* Flag indicating the ready state of the client.
* Is true after `init` has retrieved methods from the server.
*/
this.isReady = false;
/**
* An object containing proxy"s to server methods.
* This object is populated after initialization completes.
*/
this.methods = {};
// Connect to the server.
var url = _const.MANIFEST_PATH;
if (!isBrowser && host) {
url = "" + host + url;
}
http.get(url).then(function (result) {
registerMethods(_this, result.methods);
})["catch"](function (err) {
throw err;
});
}
// ----------------------------------------------------------------------------
/**
* Registers a callback to be invoked when the server-proxy is ready.
* @param func: The callback function.
*/
_createClass(Client, [{
key: "onReady",
value: function onReady(func) {
if (this.isReady) {
// Already initialized - invoke callback immediately.
if (_lodash2["default"].isFunction(func)) {
func();
}
} else {
// Store callback to invoke later.
this[STATE].readyHandlers.push(func);
}
return this;
}
/**
* Invokes the specified method taking an array of parameters.
*
* @param verb: The HTTP verb (GET/PUT/POST/DELETE).
* @param methodName: The name/key of the method to invoke.
* @param args: Optional. The arguments to pass to the method.
*
* @return promise.
*/
}, {
key: "invoke",
value: function invoke(verb, methodName) {
var args = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
// Setup initial conditions.
if (!_lodash2["default"].isArray(args)) {
args = [args];
}
if (!this.isReady) {
throw new Error("Initializion must be complete before invoking methods. See \"isReady\" flag.");
}
// Invoke the method.
var method = this[STATE].methods[methodName];
if (!method || !method.verbs[verb.toLowerCase()]) {
throw new Error("Failed to invoke. A " + verb + " method \"" + methodName + "\" does not exist.");
}
return method.invoke(verb, args);
}
// HTTP verb specific invoker methods.
}, {
key: "get",
value: function get(methodName) {
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
return this.invoke("GET", methodName, args);
}
}, {
key: "put",
value: function put(methodName) {
for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
args[_key3 - 1] = arguments[_key3];
}
return this.invoke("PUT", methodName, args);
}
}, {
key: "post",
value: function post(methodName) {
for (var _len4 = arguments.length, args = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
args[_key4 - 1] = arguments[_key4];
}
return this.invoke("POST", methodName, args);
}
}, {
key: "delete",
value: function _delete(methodName) {
for (var _len5 = arguments.length, args = Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
args[_key5 - 1] = arguments[_key5];
}
return this.invoke("DELETE", methodName, args);
}
}]);
return Client;
})();
exports["default"] = function (options) {
return new Client(options);
};