UNPKG

mws-sdk-async

Version:

A simple class based approach to work with Amazon's Merchant Web Services APIs.

208 lines (175 loc) 6.24 kB
const { promisify } = require('util'); const crypto = require('crypto'); const request = require('request-promise-native'); const qs = require('querystring'); const _ = require('lodash'); /** Promisify callbacks */ const parseString = promisify(require('xml2js').parseString); /** Base level representation of an Amazon Merchant Web Service Call */ class MWS { /** * * @param {object} config - object containing the following * @example marketplaceId - default used when not specifically needed by a call * @example sellerId - seller id for your store * @example authToken - MWS authentication token * @example accessKeyId - MWS access key * @example secretKey - MWS secret key */ constructor(config = undefined) { /** Bind Context */ this.makeCall = this.makeCall.bind(this); MWS.formatQuery = MWS.formatQuery.bind(this); MWS.XMLToJSON = MWS.XMLToJSON.bind(this); if (!config) { this.parseEnv(); } else { this.parseConfig(config); } this.xml_options = { ignoreAttrs: false, explicitRoot: false, explicitArray: false }; } /** * Formats params from a specific call into the basic format * all calls use * @param {object} params - json object of parameters passed from * down the inheritance chain on a specific call */ async makeCall(params, resolveWithFullResponse = false) { const call = { url: `https://${this.host}:443/${params.path}/${params.version}`, method: params.method, headers: { Host: this.host, 'User-Agent': 'OMS/1.0 (language=Javascript)', 'Content-Type': 'x-www-form-urlencoded', // 'Content-Type': 'text/xml', }, responseFormat: 'json', qs: null, resolveWithFullResponse, }; if (params.body) { call.body = params.body; } const query = MWS.formatQuery(params); /** Create the string to sign */ const stringToSign = [ params.method, this.host, `/${params.path}/${params.version}`, qs.stringify(query), ].join('\n'); /** Sign the query */ query.Signature = crypto .createHmac('sha256', this.secretKey) .update(stringToSign) .digest('base64'); /** If the method has a form option then add the query to the http body */ if (params.form) { call.form = qs.stringify(query); } else { call.qs = query; } try { return request(call); } catch (e) { if (e.statusCode === 503) { throw new Error('Warning! Request Throttled'); } throw e; } } /** * Calculate the MD5 hash of a string * * @param {String} string - The string (or buffer). * @return {String} - The MD5 Hash */ static generateMD5(string) { return crypto.createHash('md5').update(string).digest('base64'); } /** * Formats a query, converts to array, then sorts and returns the array * @param {object} params - parameters from a call on a specific API */ static formatQuery(params) { const BASE_QUERY = { SignatureVersion: 2, Timestamp: new Date().toISOString(), Version: params.version, SignatureMethod: 'HmacSHA256', AWSAccessKeyId: this.accessKeyId, SellerId: this.sellerId, MWSAuthToken: this.authToken, MarketplaceId: this.marketplaceId, }; /** Append parameters to the query */ _.keys(params.query).forEach((key) => { if (key.indexOf('MarketplaceId') >= 0) { delete BASE_QUERY.MarketplaceId; } if (params.query[key] !== null) { BASE_QUERY[key] = params.query[key]; } }); /** Sort the query */ const keys = _.keys(BASE_QUERY); const sortedQuery = {}; keys.sort(); keys.forEach((key) => { sortedQuery[key] = BASE_QUERY[key]; }); return sortedQuery; } /** * Allows the user to provide ENV variables instead of a configuration object * Requires access to the following Environment variables * @example MWS_HOST (not required, defaults to mws.amazonservices.com) * @example MWS_MARKETPLACE_ID * @example MWS_SELLER_ID * @example MWS_AUTH_TOKEN * @example MWS_ACCESS_KEY * @example MWS_SECRET_KEY */ parseEnv() { const { MWS_HOST, MWS_MARKETPLACE_ID, MWS_SELLER_ID, MWS_AUTH_TOKEN, MWS_ACCESS_KEY, MWS_SECRET_KEY, } = process.env; if (!MWS_MARKETPLACE_ID) throw Error('If using environment variables, you must include MWS_MARKETPLACE_ID'); if (!MWS_SELLER_ID) throw Error('If using environment variables, you must include MWS_SELLER_ID'); if (!MWS_AUTH_TOKEN) throw Error('If using environment variables, you must include MWS_AUTH_TOKEN'); if (!MWS_ACCESS_KEY) throw Error('If using environment variables, you must include MWS_ACCESS_KEY'); if (!MWS_SECRET_KEY) throw Error('If using environment variables, you must include MWS_SECRET_KEY'); this.host = MWS_HOST || 'mws.amazonservices.com'; this.sellerId = MWS_SELLER_ID; this.authToken = MWS_AUTH_TOKEN; this.accessKeyId = MWS_ACCESS_KEY; this.secretKey = MWS_SECRET_KEY; this.marketplaceId = MWS_MARKETPLACE_ID; return true; } parseConfig(config) { if (!config.marketplaceId) throw Error('If using a configuration object, you must include marketplaceId'); if (!config.sellerId) throw Error('If using a configuration object, you must include sellerId'); if (!config.authToken) throw Error('If using a configuration object, you must include authToken'); if (!config.accessKeyId) throw Error('If using a configuration object, you must include accessKeyId'); if (!config.secretKey) throw Error('If using a configuration object, you must include secretKey'); this.host = config.mwsHost || 'mws.amazonservices.com'; this.sellerId = config.sellerId; this.authToken = config.authToken; this.accessKeyId = config.accessKeyId; this.secretKey = config.secretKey; this.marketplaceId = config.marketplaceId; return true; } static async XMLToJSON(xml, opts = {}) { const xmlOptions = { ...this.xml_options, ...opts }; return parseString(xml, xmlOptions); } } // end MWS Class module.exports = MWS;