layer-api
Version:
Node.js library, which provides a wrapper for the Layer Platform API
132 lines (105 loc) • 3.33 kB
JavaScript
;
/**
* HTTPS Request implementation
* @module request
*/
var https = require('https');
var utils = require('./utils');
var ResponseError = require('./errors').ResponseError;
var APIError = require('./errors').APIError;
var API = {
host: 'api.layer.com',
prefix: '/apps/',
port: 443,
methods: ['get', 'post', 'delete', 'patch', 'put']
};
/**
* Request constructor
*
* @class
* @param {Object} config Configuration values
*/
module.exports = function(config) {
this.token = config.token;
this.appId = config.appId;
// defaults for optional values
this.version = config.version || '1.0';
this.timeout = config.timeout || 10000;
if (config.agent) {
if (config.agent instanceof https.Agent) this.agent = config.agent;
else throw new Error(utils.i18n.layerapi.agent);
}
else if (config.agentOptions) {
this.agent = new https.Agent(config.agentOptions);
}
// expose request methods
API.methods.forEach(function(method) {
this[method] = request.bind(this, method);
}, this);
};
/**
* Request implementation
*
* @param {String} method HTTP method type
* @param {Object} params Parameters passed in from the resource
* @param {Function} callback Callback function
*/
function request(method, params, callback) {
var headers = {
Accept: 'application/vnd.layer+json; version=' + this.version,
Authorization: 'Bearer ' + this.token
};
if (method === 'patch') headers['Content-Type'] = 'application/vnd.layer-patch+json';
else headers['Content-Type'] = 'application/json';
if (params.dedupe) headers['If-None-Match'] = params.dedupe;
var options = {
host: API.host,
port: API.port,
path: API.prefix + this.appId + params.path,
method: method.toUpperCase(),
headers: headers
}
if (this.agent) options.agent = this.agent;
var req = https.request(options);
req.setTimeout(this.timeout, timeout.bind(this, req, callback));
req.on('error', error.bind(this, req, callback));
req.on('response', response.bind(this, callback));
req.on('socket', function(socket) {
var write = function() {
if (params.body) req.write(JSON.stringify(params.body));
req.end();
}
// reusing connection when using keepAlive agent
if (socket.authorized) write();
else socket.on('secureConnect', function() { write(); })
});
}
function response(callback, res) {
utils.debug('Response HTTP ' + res.statusCode);
var payload = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
payload += chunk;
});
res.on('end', function() {
try {
payload = JSON.parse(payload);
} catch(e) {
// We can safely ignore this. If not JSON it's probably a string.
utils.debug('Error parsing JSON payload: ' + e);
}
if (res.statusCode >= 300) callback(new ResponseError(res.statusCode, payload));
else callback(null, {status: res.statusCode, body: payload});
});
}
function error(req, callback, err) {
if (req._isAborted) return;
utils.debug('Request error: ' + err);
callback(err);
}
function timeout(req, callback) {
utils.debug('Request timeout error after ' + this.timeout / 1000 + 'seconds');
req._isAborted = true;
req.abort();
callback(new APIError('Request timeout after ' + this.timeout / 1000 + 'seconds.'));
}