Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

heroku-client

Package Overview
Dependencies
Maintainers
1
Versions
72
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

heroku-client - npm Package Compare versions

Comparing version 0.3.1 to 0.3.2

10

lib/heroku.js

@@ -1,3 +0,3 @@

var client = require('./request'),
_ = require('underscore');
var Request = require('./request'),
_ = require('lodash');

@@ -10,3 +10,3 @@ module.exports = Heroku;

Heroku.request = client.request;
Heroku.request = Request.request;

@@ -18,6 +18,6 @@ Heroku.prototype.request = function (options, callback) {

} else {
options = _.extend(_.clone(this.options), options);
options = _.defaults(options, this.options);
}
return Heroku.request(options, function (err, body) {
return Request.request(options, function (err, body) {
if (callback) callback(err, body);

@@ -24,0 +24,0 @@ });

var https = require('https'),
memjs = require('memjs'),
q = require('q'),
_ = require('underscore'),
_ = require('lodash'),
cache;
exports.request = function request(options, callback) {
options || (options = {});
var deferred = q.defer(),
path = options.path;
module.exports = Request;
getCache(path, options.cacheKeyPostfix, function(cachedResponse) {
var headers = _.extend({
'Accept': 'application/vnd.heroku+json; version=3',
'Content-type': 'application/json'
}, options.headers || {});
if (cachedResponse) {
headers['If-None-Match'] = cachedResponse.etag;
}
/*
* Create an object capable of making API
* calls. Accepts custom request options and
* a callback function.
*/
function Request (options, callback) {
this.options = options || {};
this.callback = callback;
this.deferred = q.defer();
var requestOptions = {
hostname: 'api.heroku.com',
port: 443,
path: path,
auth: ':' + options.token,
method: options.method || 'GET',
headers: headers
};
_.bindAll(this); }
var req = https.request(requestOptions, function(res) {
if (res.statusCode === 304 && cachedResponse) {
deferred.resolve(cachedResponse.body);
callback(null, cachedResponse.body);
} else {
var buffer = '';
res.on('data', function(data) {
buffer += data;
});
/*
* Instantiate a Request object and makes a
* request, returning the request promise.
*/
Request.request = function request (options, callback) {
var req = new Request(options, function (err, body) {
if (callback) callback(err, body);
});
res.on('end', function() {
if (expectedStatus(res, options)) {
handleSuccess(res, buffer, options, deferred, callback);
} else {
handleFailure(res, buffer, options, deferred, callback);
}
});
return req.request();
};
/*
* Check for a cached response, then
* perform an API request. Return the
* request object's promise.
*/
Request.prototype.request = function request () {
this.getCache(this.performRequest);
return this.deferred.promise;
};
/*
* Perform the actual API request.
*/
Request.prototype.performRequest = function performRequest (cachedResponse) {
var headers,
requestOptions,
req;
this.cachedResponse = cachedResponse;
headers = _.extend({
'Accept': 'application/vnd.heroku+json; version=3',
'Content-type': 'application/json'
}, this.options.headers || {});
if (this.cachedResponse) {
headers['If-None-Match'] = this.cachedResponse.etag;
}
requestOptions = {
hostname: 'api.heroku.com',
port: 443,
path: this.options.path,
auth: ':' + this.options.token,
method: this.options.method || 'GET',
headers: headers
};
req = https.request(requestOptions, this.handleResponse);
this.writeBody(req);
this.setRequestTimeout(req);
req.on('error', this.handleError);
req.end();
};
/*
* If the cache client is alive, get the
* cached response from the cache.
*/
Request.prototype.getCache = function getCache (callback) {
if (!cache) return callback(null);
var key = this.options.path + '-' + this.options.cacheKeyPostfix;
cache.get(key, function (err, res) {
callback(JSON.parse(res));
});
};
/*
* Handle an API response, returning the
* cached body if it's still valid, or the
* new API response.
*/
Request.prototype.handleResponse = function handleResponse (res) {
var _this = this,
buffer;
if (res.statusCode === 304 && this.cachedResponse) {
this.deferred.resolve(this.cachedResponse.body);
this.callback(null, this.cachedResponse.body);
} else {
buffer = '';
res.on('data', function (data) {
buffer += data;
});
res.on('end', function () {
if (_this.expectedStatus(res)) {
_this.handleSuccess(res, buffer);
} else {
_this.handleFailure(res, buffer);
}
});
}
};
if (options.body) {
var body = JSON.stringify(options.body);
req.setHeader('Content-length', body.length);
req.write(body);
}
/*
* If the request options include a body,
* write the body to the request and set
* an appropriate 'Content-length' header.
*/
Request.prototype.writeBody = function writeBody (req) {
if (!this.options.body) return;
req.on('error', function(err) {
deferred.reject(err);
callback(err);
});
var body = JSON.stringify(this.options.body);
if (options.timeout && options.timeout > 0) {
req.setTimeout(options.timeout, function() {
req.abort();
req.setHeader('Content-length', body.length);
req.write(body);
}
var err = new Error('Request took longer than ' + options.timeout + 'ms to complete.');
deferred.reject(err);
callback(err);
});
}
req.end();
/*
* If the request options include a timeout,
* set the timeout and provide a callback
* function in case the request exceeds the
* timeout period.
*/
Request.prototype.setRequestTimeout = function setRequestTimeout (req) {
var _this = this;
if (!this.options.timeout) return;
req.setTimeout(this.options.timeout, function () {
var err = new Error('Request took longer than ' + _this.options.timeout + 'ms to complete.');
req.abort();
_this.deferred.reject(err);
_this.callback(err);
});
}
return deferred.promise;
/*
* In the event of an error in performing
* the API request, reject the deferred
* object and return an error to the callback.
*/
Request.prototype.handleError = function handleError (err) {
this.deferred.reject(err);
this.callback(err);
}
function expectedStatus(res, options) {
/*
* Check that the status from the API response
* matches the one(s) that are expected.
*/
Request.prototype.expectedStatus = function expectedStatus (res) {
var options = this.options;
if (options.expectedStatus) {

@@ -93,6 +199,16 @@ if (Array.isArray(options.expectedStatus)) {

function handleFailure(res, buffer, options, deferred, callback) {
var statusString = options.expectedStatus,
message;
/*
* In the event of a non-successful API request,
* fail with an appropriate error message and
* status code.
*/
Request.prototype.handleFailure = function handleFailure (res, buffer) {
var options = this.options,
callback = this.callback,
deferred = this.deferred,
statusString = options.expectedStatus,
message,
err;
if (options.expectedStatus) {

@@ -108,3 +224,3 @@ if (Array.isArray(options.expectedStatus)) {

var err = new Error(message);
err = new Error(message);
err.statusCode = res.statusCode;

@@ -117,7 +233,16 @@ err.body = JSON.parse(buffer || "{}");

function handleSuccess(res, buffer, options, deferred, callback) {
var body = JSON.parse(buffer || '{}');
setCache(options.path, options.cacheKeyPostfix, res, body);
/*
* In the event of a successful API response,
* write the response to the cache and resolve
* with the response body.
*/
Request.prototype.handleSuccess = function handleSuccess (res, buffer) {
var options = this.options,
callback = this.callback,
deferred = this.deferred,
body = JSON.parse(buffer || '{}');
this.setCache(options.path, options.cacheKeyPostfix, res, body);
deferred.resolve(body);

@@ -127,17 +252,15 @@ callback(null, body);

function getCache(path, postfix, callback) {
if (!cache) return callback(null);
var key = path + '-' + postfix;
/*
* If the cache client is alive, write the
* provided response and body to the cache.
*/
Request.prototype.setCache = function setCache (path, cacheKeyPostfix, res, body) {
var key, value;
cache.get(key, function(err, res) {
callback(JSON.parse(res));
});
}
function setCache(path, cacheKeyPostfix, res, body) {
if ((!cache) || !(res.headers.etag)) return;
var key = path + '-' + cacheKeyPostfix;
var value = JSON.stringify({
key = path + '-' + cacheKeyPostfix;
value = JSON.stringify({
body: body,

@@ -150,8 +273,17 @@ etag: res.headers.etag

exports.connectCacheClient = function connectCacheClient() {
/*
* Connect a cache client.
*/
Request.connectCacheClient = function connectCacheClient() {
cache = memjs.Client.create();
};
/*
* Automatically connect a cache client if
* NODE_ENV is set to 'production'.
*/
if (process.env.NODE_ENV === 'production') {
exports.connectCacheClient();
Request.connectCacheClient();
}
var Heroku = require('./heroku'),
inflection = require('inflection'),
resources = require('./resources').resources,
_ = require('underscore');
_ = require('lodash');

@@ -6,0 +6,0 @@

{
"name": "heroku-client",
"version": "0.3.1",
"version": "0.3.2",
"description": "A wrapper for the Heroku v3 API",

@@ -28,4 +28,4 @@ "main": "./lib/heroku.js",

"inflection": "~1.2.6",
"underscore": "~1.5.1"
"lodash": "~1.3.1"
}
}

@@ -1,7 +0,8 @@

var Heroku = require('../../lib/heroku'),
heroku = new Heroku({ token: '12345' });
var Heroku = require('../../lib/heroku'),
Request = require('../../lib/request'),
heroku = new Heroku({ token: '12345' });
describe('Heroku', function() {
beforeEach(function() {
spyOn(Heroku, 'request').andCallFake(function(options, callback) {
spyOn(Request, 'request').andCallFake(function(options, callback) {
callback();

@@ -13,3 +14,3 @@ });

heroku.apps('my-app').create({}, function() {
expect(Heroku.request.mostRecentCall.args[0].method).toEqual('POST');
expect(Request.request.mostRecentCall.args[0].method).toEqual('POST');
done();

@@ -21,3 +22,3 @@ });

heroku.apps('my-app').dynos().list(function() {
expect(Heroku.request.mostRecentCall.args[0].expectedStatus).toEqual([200, 206]);
expect(Request.request.mostRecentCall.args[0].expectedStatus).toEqual([200, 206]);
done();

@@ -30,3 +31,3 @@ });

heroku.apps().list(function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps');
done();

@@ -38,3 +39,3 @@ });

heroku.apps('my-app').info(function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps/my-app');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps/my-app');
done();

@@ -46,3 +47,3 @@ });

heroku.apps('my-app').collaborators('jonathan@heroku.com').info(function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/collaborators/jonathan@heroku.com');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/collaborators/jonathan@heroku.com');
done();

@@ -56,3 +57,3 @@ });

heroku.apps().create({ name: 'my-app' }, function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps');
done();

@@ -64,3 +65,3 @@ });

heroku.apps().create({ name: 'my-new-app' }, function() {
expect(Heroku.request.mostRecentCall.args[0].body).toEqual({ name: 'my-new-app' });
expect(Request.request.mostRecentCall.args[0].body).toEqual({ name: 'my-new-app' });
done();

@@ -74,3 +75,3 @@ });

heroku.apps('my-app').addons().create({ name: 'papertrail:choklad' }, function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/addons');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/addons');
done();

@@ -82,3 +83,3 @@ });

heroku.apps('my-app').addons().create({ name: 'papertrail:choklad' }, function() {
expect(Heroku.request.mostRecentCall.args[0].body).toEqual({ name: 'papertrail:choklad' });
expect(Request.request.mostRecentCall.args[0].body).toEqual({ name: 'papertrail:choklad' });
done();

@@ -92,3 +93,3 @@ });

heroku.apps('my-app').addons('papertrail:choklad').update({ name: 'papertrail:fixa' }, function() {
expect(Heroku.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/addons/papertrail:choklad');
expect(Request.request.mostRecentCall.args[0].path).toEqual('/apps/my-app/addons/papertrail:choklad');
done();

@@ -100,3 +101,3 @@ });

heroku.apps('my-app').addons('papertrail:choklad').update({ name: 'papertrail:fixa' }, function() {
expect(Heroku.request.mostRecentCall.args[0].body).toEqual({ name: 'papertrail:fixa' });
expect(Request.request.mostRecentCall.args[0].body).toEqual({ name: 'papertrail:fixa' });
done();

@@ -103,0 +104,0 @@ });

var https = require("https"),
client = require('../../lib/request'),
Request = require('../../lib/request'),
memjs = require('memjs'),

@@ -156,3 +156,3 @@ MockCache = require('../helpers/mockCache'),

spyOn(memjs.Client, 'create').andReturn(cache);
client.connectCacheClient();
Request.connectCacheClient();
});

@@ -203,9 +203,9 @@

spyOn(https, 'request').andCallFake(function(options, httpsCallback) {
var req = new MockRequest();
var res = new MockResponse(testOptions.response || {});
spyOn(https, 'request').andCallFake(function (options, httpsCallback) {
var req = new MockRequest(),
res = new MockResponse(testOptions.response || {});
httpsCallback(res);
setTimeout(function() {
setTimeout(function () {
res.emit('data', '{ "message": "ok" }');

@@ -219,5 +219,5 @@ if (!req.isAborted) res.emit('end');

return client.request(options, function(err, body) {
return Request.request(options, function (err, body) {
if (callback) callback(err, body);
});
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc