mozu-node-sdk
Version:
Mozu JavaScript SDK for Node.js and Arc.js environments
139 lines (129 loc) • 5.16 kB
JavaScript
/* eslint-disable complexity */
;
var constants = require('../constants');
var extend = require('./tiny-extend');
var url = require('url');
var protocolHandlers = {
'http:': require('http'),
'https:': require('https')
};
var streamToCallback = require('./stream-to-callback');
var parseJsonDates = require('./parse-json-dates');
var errorify = require('./errorify');
var zlib = require('zlib');
var ACCEPT_ENCODING = '';
if( zlib.createBrotliDecompress && zlib.createGunzip ){
ACCEPT_ENCODING ='br;q=1.0, gzip;q=0.8';
}else if(zlib.createGunzip){
ACCEPT_ENCODING = 'gzip;q=1.0'
}
var USER_AGENT = 'Mozu Node SDK v' + constants.version + ' (Node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')';
/**
* Handle headers
*/
function makeHeaders(conf, payload) {
var headers;
function iterateHeaders(memo, key) {
if (conf.context[constants.headers[key]]) {
if (key === 'JWT') {
memo[constants.jwtHeader] = conf.context[constants.headers[key]].indexOf(constants.jwtHeaderValuePrefix) === -1 ?
constants.jwtHeaderValuePrefix + conf.context[constants.headers[key]] :
conf.context[constants.headers[key]];
} else {
memo[constants.headerPrefix + constants.headers[key]] = conf.context[constants.headers[key]];
}
}
return memo;
}
if (conf.scope && conf.scope & constants.scopes.NONE) {
headers = {};
} else if (conf.scope && conf.scope & constants.scopes.APP_ONLY) {
headers = ['APPCLAIMS'].reduce(iterateHeaders, {});
} else {
headers = Object.keys(constants.headers).reduce(iterateHeaders, {});
}
if (payload) {
headers['Content-Length'] = payload.length.toString();
}
if (headers['Authorization'] && headers['x-vol-user-claims']) delete headers['x-vol-user-claims'];
if (headers['Authorization'] && headers['x-vol-app-claims']) delete headers['x-vol-app-claims'];
return extend({
'Accept': 'application/json',
'Accept-Encoding': ACCEPT_ENCODING,
'Connection': 'close',
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': USER_AGENT
}, headers, conf.headers || {});
}
/**
* Make an HTTP request to the Mozu API. This method populates headers based on the scope of the supplied context.
* @param {Object} options The request options, to be passed to the `request` module. Look up on NPM for details.
* @return {Promise<ApiResponse,ApiError>} A Promise that will fulfill as the JSON response from the API, or reject with an error as JSON from the API.
*/
module.exports = function(options, transform) {
var conf = extend({}, options);
conf.method = (conf.method || 'get').toUpperCase();
var payload;
if (conf.body) {
payload = conf.body;
if (typeof payload !== "string" && !Buffer.isBuffer(payload)) {
payload = JSON.stringify(payload);
}
if ( typeof payload === "string"){
payload = new Buffer(payload);
}
}
conf.headers = makeHeaders(conf, payload);
var uri = url.parse(conf.url);
var protocolHandler = protocolHandlers[uri.protocol];
if (!protocolHandler) {
throw new Error('Protocol ' + uri.protocol + ' not supported.');
}
return new Promise(function(resolve, reject) {
options = extend({}, options);
delete options.headers;
var requestOptions = extend({
hostname: uri.hostname,
port: uri.port || (uri.protocol === 'https:' ? 443 : 80),
method: conf.method,
path: uri.path,
headers: conf.headers,
agent: conf.agent
}, options);
if (typeof transform === "function") {
requestOptions = transform(requestOptions);
}
var complete = false;
var request = protocolHandler.request(requestOptions, function(response) {
streamToCallback(response, function(err, body) {
complete = true;
if (err) return reject(errorify(err, extend({ statusCode: response.statusCode, url: response.req.path}, response.headers)));
if (body) {
try {
if(response.headers["content-type"] && (response.headers["content-type"].indexOf('json') > -1 || response.headers["content-type"].indexOf('text/plain') > -1)) {
body = JSON.parse(body, (conf.parseDates !== false) && parseJsonDates);
}
} catch(e) {
return reject(new Error('Response was not valid JSON: ' + e.message + '\n\n-----\n' + body));
}
}
if (response && response.statusCode >= 400 && response.statusCode < 600) {
return reject(errorify(body || response, extend({ statusCode: response.statusCode, url: (response.req ? response.req.path : "")}, response.headers)));
}
return resolve(body);
});
});
var timeout = options.timeout || 20000;
request.setTimeout(timeout, function() {
if (!complete) {
request.abort();
reject(errorify("Timeout occurred: request to " + conf.url + " took more than " + timeout / 1000 + " seconds to complete."));
}
});
request.on('error', function(err) {
reject(errorify(err, request));
});
if (payload) request.write(payload);
request.end();
});
};