mws-zodane-advanced
Version:
fixed throtal resend
291 lines (262 loc) • 18.2 kB
HTML
<html>
<head>
<meta charset="utf-8">
<base data-ice="baseUrl" href="../../">
<title data-ice="title">lib/callEndpoint.js | mws-advanced</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
<script src="script/prettify/prettify.js"></script>
<script src="script/manual.js"></script>
</head>
<body class="layout-container" data-ice="rootContainer">
<header>
<a href="./">Home</a>
<a href="identifiers.html">Reference</a>
<a href="source.html">Source</a>
<div class="search-box">
<span>
<img src="./image/search.png">
<span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
</span>
<ul class="search-result"></ul>
</div>
</header>
<nav class="navigation" data-ice="nav"><div>
<ul>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~InvalidUsage.html">InvalidUsage</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~RequestCancelled.html">RequestCancelled</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~ServiceError.html">ServiceError</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~ValidationError.html">ValidationError</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-callEndpoint">callEndpoint</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-init">init</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getLowestPricedOffersForASIN">getLowestPricedOffersForASIN</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getMarketplaces">getMarketplaces</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getMatchingProductForId">getMatchingProductForId</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listFinancialEvents">listFinancialEvents</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listInventorySupply">listInventorySupply</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listOrderItems">listOrderItems</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listOrders">listOrders</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReport">getReport</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportList">getReportList</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportListAll">getReportListAll</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportListByNextToken">getReportListByNextToken</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportRequestList">getReportRequestList</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-requestAndDownloadReport">requestAndDownloadReport</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-requestReport">requestReport</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MWS_ENDPOINTS">MWS_ENDPOINTS</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MWS_MARKETPLACES">MWS_MARKETPLACES</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-BuyBoxPrice">BuyBoxPrice</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-DetailedShippingTime">DetailedShippingTime</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-LowestPrice">LowestPrice</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-LowestPricedOffers">LowestPricedOffers</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-Money">Money</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-Offer">Offer</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OfferCount">OfferCount</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OfferSummary">OfferSummary</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-SellerFeedbackRating">SellerFeedbackRating</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-ShipsFrom">ShipsFrom</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-MarketDetail">MarketDetail</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OrderItemList">OrderItemList</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-GetReportRequestListResult">GetReportRequestListResult</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-GetReportRequestListResult">GetReportRequestListResult</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-ReportRequestInfo">ReportRequestInfo</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#endpoints">endpoints</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-REPORT_PROCESSING_STATUS_TYPES">REPORT_PROCESSING_STATUS_TYPES</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-REQUEST_REPORT_TYPES">REQUEST_REPORT_TYPES</a></span></span></li>
</ul>
</div>
</nav>
<div class="content" data-ice="content"><h1 data-ice="title">lib/callEndpoint.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">const MWS = require('mws-simple');
const { MWS_ENDPOINTS } = require('./constants');
const sleep = require('./util/sleep');
const fs = require('fs');
const errors = require('./errors.js');
/*
* TODO: split the "init" function out of the "callEndpoint" file, difficulty: callEndpoint
* depends on having init modify the mws value, which doesn't carry between module pieces in that
* case -- exporting 'mws' to callEndpoint just results in null every time it's accessed, even
* when requiring it inline in code, rather than at the top of the file. Ugh. Big design
* problem, that is a holdover from when the entire module was all located in a single file.
*/
/** holds the mws-simple reference after init() is called */
let mws = null;
/**
* Initialize mws-advanced with your MWS access keys, merchantId, optionally authtoken, host, port
* If accessKeyId, secretAccessKey, and/or merchantId are not provided, they will be read from
* the environment variables MWS_ACESS_KEY, MWS_SECRET_ACCESS_KEY, and MWS_MERCHANT_ID respectively
*
* @public
* @example
* const mws = MWS.init({ region: 'NA', accessKeyId: '1234', secretAccessKey: '2345', merchantId: '1234567890' });
* const mws = MWS.init({ region: 'EU', accessKeyId, ... });
* const mws = MWS.init({ authToken: 'qwerty', accessKeyId, ...});
* const mws = MWS.init({ host: 'alternate-mws-server.com', accessKeyId, ... });
* @param {object} config Contains your MWS Access Keys/Tokens and options to configure the API
* @param {string} [config.accessKeyId=process.env.MWS_ACCESS_KEY] Your MWS Access Key
* @param {string} [config.secretAccessKey=process.env.MWS_SECRET_ACCESS_KEY] Your MWS Secret Access Key
* @param {string} [config.merchantId=process.env.MWS_MERCHANT_ID] Your MWS Merchant ID
* @param {string} [config.authToken] If making a call for a third party account, the Auth Token provided
* for the third party account
* @param {string} [config.region='NA'] One of the Amazon regions as specified in https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
* @param {string} [config.host='mws.amazonservices.com'] Set MWS host server name, see https://docs.developer.amazonservices.com/en_US/dev_guide/DG_Endpoints.html
* @param {number} [config.port=443] Set MWS host port
* @returns {mws-simple} - The mws-simple instance used to communicate with the API
*/
const init = ({
region = 'NA',
// marketplace = 'US', // TODO: maybe someday we will want to keep track of a 'default' marketplace.
accessKeyId = process.env.MWS_ACCESS_KEY,
secretAccessKey = process.env.MWS_SECRET_ACCESS_KEY,
merchantId = process.env.MWS_MERCHANT_ID,
authToken,
host = MWS_ENDPOINTS[region] || 'mws.amazonservices.com',
port,
} = {}) => {
mws = new MWS({
accessKeyId,
secretAccessKey,
merchantId,
authToken,
host,
port,
});
return mws;
};
const { flattenResult } = require('./flatten-result');
const { validateAndTransformParameters } = require('./validation');
const { digResponseResult } = require('./dig-response-result.js');
// TODO: add Subscriptions and Recommendations categories
const {
feeds, finances, inbound, inventory, outbound,
merchFulfillment, orders, products, sellers, reports,
} = require('./endpoints');
// TODO: THIS MAY BE A BAD IDEA CONSIDERING THAT SOME CATEGORIES SHARE SOME ENDPOINT NAMES
// TODO: WE MAY NEED TO COME UP WITH A WAY TO DEAL WITH THAT.
/** simple flat list of all the endpoints required from individual modules above */
const endpoints = {
...feeds,
...finances,
...inbound,
...inventory,
...merchFulfillment,
...orders,
...outbound,
...products,
...sellers,
...reports,
};
/**
* Return a promise for making the desired request, flattening the response out to something
* that will hopefully make a little more sense.
*
* @async
* @private
* @param {any} requestData
* @param {object} [opt] - options
* @param {boolean} [opt.noFlatten] - do not run flattenResult on the output
*/
const requestPromise = (requestData, opt = {}) =>
new Promise((resolve, reject) => {
// eslint-disable-next-line global-require
mws.request(requestData, (err, result) => {
if (err) {
reject(err);
} else {
resolve(opt.noFlatten ? result : flattenResult(result));
}
});
});
/**
* Call a known endpoint at MWS, returning the raw data from the function. Parameters are
* transformed and validated according to the rules defined in lib/endpoints
*
* @async
* @public
* @param {string} name - name of MWS API function to call
* @param {object} [callOptions] - named hash object of the parameters to pass to the API
* @param {object} [opt] - options for callEndpoint
* @param {boolean} [opt.noFlatten] - do not flatten results
* @param {boolean} [opt.returnRaw] - return only the raw data (may or may not be flattened)
* @param {string} [opt.saveRaw] - filename to save raw data to (may or may not be flattened)
* @param {string} [opt.saveParsed] - filename to save final parsed data to (not compatible with returnRaw, since parsing won't happen)
* @returns {any} - Results of the call to MWS
*/
const callEndpoint = async (name, callOptions = {}, opt = {}) => {
const endpoint = endpoints[name];
if (!endpoint) {
throw new errors.InvalidUsage('No endpoint name supplied to callEndpoint');
}
const newOptions = endpoint.params ?
validateAndTransformParameters(endpoint.params, callOptions) : callOptions;
const queryOptions = {
...newOptions,
Action: endpoint.action,
Version: endpoint.version,
};
const params = {
path: `/${endpoint.category}/${endpoint.version}`,
query: queryOptions,
};
try {
const result = await requestPromise(params, { noFlatten: opt.noFlatten });
if (opt.saveRaw) {
fs.writeFileSync(opt.saveRaw, JSON.stringify(result));
}
if (opt.returnRaw) {
return result;
}
const digResult = digResponseResult(name, result);
if (opt.saveParsed) {
fs.writeFileSync(opt.saveParsed, JSON.stringify(digResult));
}
return digResult;
} catch (err) {
if (err instanceof MWS.ServerError) {
if (err.code === 503) {
console.warn('***** Error 503 .. throttling?', name);
let ms = 2000;
if (!endpoint.throttle) {
console.warn(`***** throttle information missing for API ${name}`);
console.warn('***** ', JSON.stringify(endpoint));
} else {
// restoreRate = how many you get back in a minute of time. there's an assumption here
// that you're spamming a lot of requests if you're hitting throttling, and this
// throttle management system is first version, here -- so we're going to throttle it
// not to the minimum possible time frame, but to the length of time that it will take
// to restore your entire maxInFlight -- assuming you're probably going to hit the max
// again as soon as we start letting more requests in.
// ultimately, an upgraded version of this throttling handler would keep track of how
// many of every request are in flight, and try to throttle it to the minimum amount
// of time that you can go, automatically throttling future calls without having to
// even encounter the 503 from the server.
// that day is not today. it might be tomorrow. maybe next weekend. i don't know. :-)
const restoreMaxInFlightMin = (endpoint.throttle.maxInFlight / endpoint.throttle.restoreRate) * (callOptions.IdList ? callOptions.IdList.length : 1);
ms = (restoreMaxInFlightMin * 60 * 1000) + 100;
}
console.warn(`***** trying again in ${ms}ms`);
await sleep(ms + 100);
return callEndpoint(name, callOptions, opt);
}
}
throw err;
}
};
module.exports = {
init,
callEndpoint,
};
</code></pre>
</div>
<footer class="footer">
Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.0.4)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>
<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>