twiliojs-api
Version:
Module to invoke twilio.com services
150 lines (117 loc) • 5.45 kB
JavaScript
/*
* Module's dependencies
*/
var request = require("request");
var Util = function(settings) {
var self = this;
// For each method metadata, it adds a new public method to the instance
this.hook = function (target, methods) {
if ( !target || typeof target !== 'object' ) throw new Error("Invalid 'target' argument. It must be an object instance.");
if ( !methods || typeof methods !== 'object' ) throw new Error("Invalid 'methods' argument. It must be an object instance.");
// creates every single method
Object.keys(methods)
.forEach(function (groupName) {
var group = methods[groupName];
Object.keys(group)
.forEach(function (methodName) {
var info = group[methodName];
validatesMethodInfo(groupName,info);
target[methodName] = createMethod(methodName, info);
});
});
};
this.validateParams = function (data, params) {
if (!data || typeof data !== 'object') throw new Error("Invalid 'data' argument. It must be an object instance.");
if (!(params instanceof Array)) throw new Error("Invalid 'params' argument. It must be an string array.");
for (var index in params) {
var param = params[index];
if (data[param]===undefined || data[param]===null) {
return new Error("'" + param + "' option is required.");
}
}
};
this.buildResponse = function (response) {
var res = {
headers: response.headers,
statusCode: response.statusCode
};
if (response.body) res.body = parseBody(response.body);
return res;
};
var parseBody = function (body) {
if( typeof body === 'string') return JSON.parse(body);
if( typeof body === 'object') return body;
};
var getUserKey = function(username, password) {
return username + ":" + password;
};
var createMethod = function(name, info) {
var requiredParams = getParamsFromPath(info.path);
return function(options, cb) {
// manage optional options
if (!cb && typeof options === 'function') {
cb = options;
options = null;
};
// validates cb
cb = cb || function(err) { if(err) throw err; };
if (typeof cb !== 'function') throw new Error("'cb' argument is invalid.");
// validates options
options = options || {};
if (typeof options !== 'object') return cb(new Error("'options' argument is invalid."));
// validates required parameters
var err = self.validateParams(options, requiredParams);
if (err) return cb(err);
//
var endpoint = settings.apiEndpoint + supplant(info.path, options);
// Sets HTTP request options
var reqOptions = {
method: info.method || "GET",
url: endpoint + '.json',
headers: {
Authorization: "Basic " + new Buffer(settings.accountSid + ":" + settings.accountToken).toString('base64')
}
};
if (reqOptions.method==="GET") {
reqOptions.json = options;
}
else {
reqOptions.form = options;
}
// Invokes Twilio's servers
request(reqOptions, function (err, response) {
if (err) return cb (new Error( "There was an error executing method '" + name + "'. " + err.message ));
var twilioResponse = self.buildResponse(response);
if (response.statusCode >= 400) return cb (new Error( "Twilio reports an error executing method '" + name + "'. Message: '" + twilioResponse.body.message + "'. Code: " + twilioResponse.body.code + "'"));
cb (null, twilioResponse);
});
};
};
var validatesMethodInfo = function(groupName, info) {
// validate params
info.params = info.params || {}
if (typeof info.params !== 'object') throw new Error("Invalid method's params. " + JSON.stringify(info));
// validate method
info.method = info.method || "GET";
if (typeof info.method !== 'string') throw new Error("Invalid HTTP method. " + JSON.stringify(info));
// Twilio 'account' is the root resource for all calls
// see: http://www.twilio.com/docs/api/rest/account
if (groupName!="account") {
// validates path
if (!(info.path) || typeof info.path != 'string') throw new Error("Invalid method's path. " + JSON.stringify(info));
if (info.path[0]!=='/') throw new Error("Method's path must start with '/' character. " + JSON.stringify(info));
};
};
var getParamsFromPath = function(path) {
var results = path.match(/{([^{}]*)}/g);
return results ? results.map(function(m) { return m.substring(1, m.length-1); }) : [];
};
var supplant = function(pattern, data) {
return pattern.replace(/{([^{}]*)}/g,
function (a, b) {
var r = data[b];
return typeof r === 'string' || typeof r === 'number' ? r : r.toString();
});
};
};
module.exports = Util;