UNPKG

ias

Version:

A node client to interface with IAS soap web services

176 lines (136 loc) 4.39 kB
'use strict'; // dependencies var mustache = require('mustache'); var xml2js = require('xml2js'); var async = require('async'); var debug = require('debug')('ias'); // local dependencies var common = require('./common'); var templates = require('./templates'); var normalize = require('./normalize'); var exports = module.exports = {}; exports.common = common; /* HELPERS */ /** * Create a client to execute the SOAP requests, parse, extract and normalize the results * into js friendly data * @param {string} loginName required * @param {string} loginPassword required * @param {string} dealerId optional but some methods require it * @param {string} env IAS environment (production | test) */ exports.Client = function(loginName, loginPassword, dealerId, env, url) { if (!loginName) { throw new Error('loginName is required'); } else if (!loginPassword) { throw new Error('loginPassword is required'); } this.loginName = loginName; this.loginPassword = loginPassword; this.dealerId = dealerId || ''; this.env = env || 'production'; this.customUrl = url; }; /** * Used to make the soap request and normalize data for all supported service methods * @param {string} serviceMethod - see common.supportedServiceMethods * @param {object} data object literal for data required for the method * @param {Function} callback (err {string}, data {object || array}) */ exports.Client.prototype.getData = function(serviceMethod, data, callback) { var start = new Date().getTime(); var requestBody = null; var responseBody = null; var serviceUrl = this.customUrl || (this.env === 'production' ? common.serviceUrl : common.testServiceUrl); debug(serviceUrl); // make sure dealerId is there if necessary if (common.dealerIdRequired.indexOf(serviceMethod) > -1) { if (!this.dealerId) { return callback('dealerId is required for ' + serviceMethod); } else { data.dealerId = this.dealerId; } } // inject auth data data.authentication = common.getBaseDataObject('auth'); data.authentication.loginName = this.loginName; data.authentication.loginPassword = this.loginPassword; data.authentication.userIPAddress = '127.0.0.1'; debug('data being passed:'); debug(JSON.stringify(data, null, 4)); // waterfall functions function getTemplate(next) { templates(serviceMethod, next); } function doRequest(xmlTemplate, next) { // TODO request logging // populate template var soapPackage = mustache.render(xmlTemplate, data); requestBody = soapPackage; debug(soapPackage); // send request to IAS common.sendRequest(serviceUrl , soapPackage , common.soapActions[serviceMethod.toLowerCase()] , next); } function handleResponse(resp, body, next) { responseBody = body; debug(body); // check for non-200 http status if (resp.statusCode !== 200) { debug('handleResponse bad http code: ' + resp.statusCode); var errMsg = 'Invalid http statusCode returned (not 200) ' + resp.statusCode; if (body) { var em = body.toString().match(/<faultstring\b[^>]*>(.*?)<\/faultstring>/); errMsg = em ? em[1] : errMsg; } next(errMsg); } else { // check for returned error body = body.toString(); if (body.indexOf('<a:ErrorOccurred>true</a:ErrorOccurred>') > -1){ var c = /<a:ErrorDescription\b[^>]*>(.*?)<\/a:ErrorDescription>/; var d = body.match(c); if (d) { next(d[1]); } else { next('ErrorOccurred was returned from server, but no description.'); } } else { next(null, body.toString()); } } } function parse(body, next) { // parse xml into js xml2js.parseString(body, next); } function extract(raw, next) { debug(JSON.stringify(raw)); var result = normalize[serviceMethod](raw); next(result === null ? 'Invalid xml response structure' : null, result); } function finish(err, result) { var fullErr = { message: err , requestBody: requestBody , responseBody: responseBody }; debug(serviceMethod + ' request completed in ' + (new Date().getTime() - start) + 'ms with ' + (err || 'success')); callback(err ? fullErr : null, result); } if (common.supportedMethods.indexOf(serviceMethod) === -1) { finish('Service method not supported'); } else { async.waterfall([ getTemplate , doRequest , handleResponse , parse , extract ], finish); } };