UNPKG

route4me-node

Version:

Access Route4Me's logistics-as-a-service API using our Node.js SDK

280 lines (238 loc) 7.89 kB
"use strict"; 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var request = require("superagent"); var errors = require("./errors"); var ResponseHandler = function () { function ResponseHandler(PromiseConstructor, logger, validate, validateContext, callback) { _classCallCheck(this, ResponseHandler); var cb = "function" !== typeof callback ? function (x) { return x; } : callback; this._logger = logger; this._validate = validate; this._validateContext = validateContext; if (PromiseConstructor) { var self = this; this._p = new PromiseConstructor(function (res, rej) { self._res = res; self._rej = rej; }); } else { this._p = undefined; this._res = function (res) { return cb(null, res); }; this._rej = function (err) { return cb(err); }; } } _createClass(ResponseHandler, [{ key: "callback", value: function callback(err, res) { if (err) { return this._handleError(err, res); } return this._handleOk(res); } }, { key: "fail", value: function fail(err) { return this._rej(err); } }, { key: "getPromise", value: function getPromise() { return this._p; } }, { key: "_handleOk", value: function _handleOk(res) { this.logger.debug({ src: "route4me:request-manager:ResponseHandler:_handleOk", msg: "response ok" }); var data = this._validate(res.body, this._validateContext, res); if (data instanceof errors.Route4MeError) { // TODO: include url and method to the log message this._logger.warn({ "msg": "response validation error", "err": data }); return this.fail(data); } else if (data instanceof Error) { // TODO: include url and method to the log message this._logger.error({ "msg": "Unhandled error during validation", "err": data, "fatal": true }); return this.fail(data); } // TODO: include url and method to the log message this._logger.info({ "msg": "response ok" }); return this._res(data); } }, { key: "_handleError", value: function _handleError(err, res) { this.logger.debug({ src: "route4me:request-manager:ResponseHandler:_handleError", msg: "response error" }); var e = new errors.Route4MeApiError(err.message, res, err); // TODO: include url and method to the log message this._logger.warn({ "msg": "response error", "err": e }); return this.fail(e); } }, { key: "logger", get: function get() { return this._logger; } }]); return ResponseHandler; }(); /** * Request manager, provides * * simple API for sending HTTP requests * * a way to handle HTTP responses * * @since 0.1.0 * * @protected */ var RequestManager = function () { /** * Creates new RequestManager. All parameters are inherited from {Route4Me} * * @param {object} apiKey - see {Route4Me} * @param {object} options - see {Route4Me} * @return {RequestManager} - New Request Manager */ function RequestManager(apiKey, options) { _classCallCheck(this, RequestManager); var opt = options; this._apiKey = apiKey; this._baseUrl = opt["baseUrl"]; this._userAgent = opt["userAgent"]; this._logger = opt["logger"]; this._validate = "function" === typeof opt["validate"] ? opt["validate"] : function (ix) { return ix; }; if (true === opt["promise"]) { this.logger.debug({ src: "route4me:request-manager:RequestManager", msg: "promises: global Promise" }); this._promiseConstructor = Promise; } else if ("function" === typeof opt["promise"]) { this.logger.debug({ src: "route4me:request-manager:RequestManager", msg: "promises: explicitly defined promise-lib" }); this._promiseConstructor = opt["promise"]; } else { this.logger.debug({ src: "route4me:request-manager:RequestManager", msg: "promises: off" }); this._promiseConstructor = null; } } _createClass(RequestManager, [{ key: "_makeRequest", /** * Wrapper around {@link external:superagent} with all options applied. * * @todo TODO: rename this method!!! * @protected * * @param {object} options Request options * @param {string} options.method HTTP method * @param {string} options.path Server path * @param {object} [options.qs] Query string * @param {object} [options.body] Body * @param {null|string|function} [options.validationContext=null] * * `null` cause validation disabled (TODO: test this case) * * `string` is threated as the name of JSON Schema * * `function` will be used for validation. * @param {module:route4me-node~RequestCallback} [callback] */ value: function _makeRequest(options, callback) { var qs = options.qs || {}; /* query string */ var body = options.body || null; var form = options.form || null; var timeouts = { response: 5000, // Wait 5 seconds for the server to start sending, deadline: 10000 }; var method = options.method.toLowerCase(); if ("delete" === method) { method = "del"; } var apiUrl = void 0; if (options.url) { this.logger.debug({ src: "route4me:request-manager:RequestManager:_makeRequest", msg: "WARNING: _makeRequest called with FULL url, but MUST be called only for partial path", url: options.url }); apiUrl = options.url; } else { apiUrl = `${this._baseUrl}${options.path}`; } qs["api_key"] = this._apiKey; if (undefined === options.validationContext) { // this is just a protective wall throw new errors.Route4MeError("validationContext should not be undefined"); } var v = this._validate; var c = options.validationContext || null; if ("function" === typeof c) { v = c; c = null; } this.logger.info({ src: "route4me:request-manager:RequestManager:_makeRequest", msg: "sending request", method, url: apiUrl, queryString: qs }); var resHandler = new ResponseHandler(this._promiseConstructor, this._logger, v, c, callback); // debug only! // qs["oldUrl"] = apiUrl // apiUrl = "https://httpbin.org/get" var req = request[method](apiUrl).set("Route4Me-User-Agent", this._userAgent).timeout(timeouts).redirects(1000) // unlimited number of redirects .accept("application/json").query(qs); if (form) { req.type("multipart/form-data").field(form); } else { req.type("application/json").send(body); } req.end(function (err, res) { return resHandler.callback(err, res); }); return resHandler.getPromise(); } /** * Early cancel request * * @todo TODO: rename this method!!! * @todo TODO: write documentation * * @param {Error} error The reason the request was cancelled. * @param {module:route4me-node~RequestCallback} [callback] */ }, { key: "_makeError", value: function _makeError(error, callback) { var resHandler = new ResponseHandler(this._promiseConstructor, this._logger, this._validate, null, callback); setTimeout(function () { resHandler.fail(error); }, 0); return resHandler.getPromise(); } }, { key: "logger", get: function get() { return this._logger; } }]); return RequestManager; }(); module.exports = RequestManager;