Skip to content

Commit f78a0ad

Browse files
author
Will Myers
authored
Add hostname, port, and secure options (#6)
* Add config.hostname, config.port, and config.secure. * Update CHANGELOG.md * Update README.md
1 parent 9feafae commit f78a0ad

10 files changed

Lines changed: 140 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2.1.0 September 12, 2016
2+
- Added config.hostname, config.port, and config.secure
3+
14
2.0.0 August 24, 2016
25
- Added `accounts` resource
36
+ `accounts#all`

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ var client = require('button-client-node')('sk-XXX', {
3737

3838
##### Config
3939

40-
* `timeout`: The time in ms for network requests to abort
40+
* `timeout`: The time in ms for network requests to abort. Defaults to false.
4141
* `promise`: A function which accepts a resolver function and returns a promise. Used to integrate with the promise library of your choice (i.e. es6 Promises, Bluebird, Q, etc). If `promise` is supplied and is a function, all API functions will ignore any passed callbacks and instead return a promise.
42+
* `hostname`: Defaults to `api.usebutton.com`
43+
* `port`: Defaults to `443` if `config.secure`, else defaults to `80`.
44+
* `secure`: Whether or not to use HTTPS. Defaults to true. **N.B: Button's API is only exposed through HTTPS. This option is provided purely as a convenience for testing and development.**
4245

4346

4447
#### Node-style Callbacks

index.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
var resources = require('./lib').resources;
22
var maybePromise = require('./lib').maybePromise;
33
var request = require('./lib').request;
4+
var merge = require('./lib').merge;
5+
var compact = require('./lib').compact;
46
var version = require('./package.json').version;
57

8+
var configDefaults = {
9+
secure: true,
10+
timeout: false
11+
};
12+
613
module.exports = function client(apiKey, config) {
714
//
815
// #client provides the top-level interface to making API requests to Button.
@@ -11,6 +18,9 @@ module.exports = function client(apiKey, config) {
1118
//
1219
// @param {string} apiKey your Button API key
1320
// @param {Object=} config an optional object
21+
// @param {string=} config.hostname defaults to 'api.usebutton.com'
22+
// @param {number=} config.port defaults to 443 if config.secure else 80
23+
// @param {bool=} config.secure will use HTTPS if true and HTTP if false
1424
// @param {number=} config.timeout a timeout in ms to abort API calls
1525
// @param {Func=} config.promise a function which should return a promise
1626
// @returns {Object} a client
@@ -19,21 +29,26 @@ module.exports = function client(apiKey, config) {
1929
throw new Error('Must provide a Button API key. Find yours at https://app.usebutton.com/settings/organization');
2030
}
2131

22-
if (!config) {
23-
config = {};
24-
}
32+
config = merge(configDefaults, config);
2533

26-
var requestOptions = {
34+
var requestConfig = merge({
2735
hostname: 'api.usebutton.com',
36+
port: config.secure ? 443 : 80
37+
}, compact({
38+
hostname: config.hostname,
39+
port: config.port
40+
}));
41+
42+
var requestOptions = merge(requestConfig, {
2843
auth: apiKey + ':',
2944
headers: {
3045
'Content-Type': 'application/json',
3146
'User-Agent': 'button-client-node/' + version + ' node/' + process.versions.node
3247
}
33-
};
48+
});
3449

3550
var maybePromiseRequest = maybePromise(
36-
request(config.timeout),
51+
request(config.timeout, config.secure),
3752
config.promise
3853
);
3954

lib/merge.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ function merge() {
1616
var res = {};
1717

1818
Array.prototype.slice.call(arguments).forEach(function(obj) {
19-
Object.keys(obj).forEach(function(key) {
20-
res[key] = obj[key];
21-
});
19+
if (Object.prototype.toString.call(obj) === '[object Object]') {
20+
Object.keys(obj).forEach(function(key) {
21+
res[key] = obj[key];
22+
});
23+
}
2224
});
2325

2426
return res;

lib/request.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
'use strict';
22

33
var https = require('https');
4+
var http = require('http');
45
var parse = require('url').parse;
56
var once = require('./once');
67

7-
function request(timeout) {
8+
function request(timeout, secure) {
89
//
910
// request issues an https request. To generate a function that will issue
10-
// network requests, you must call this module with an optional timeout.
11+
// network requests, you must call this module with an optional timeout and
12+
// optional boolean for whether or not to use HTTPS.
13+
//
1114
// The returned function may then be invoked with arguments specific to a
1215
// given request.
1316
//
1417
// ## Usage
1518
//
16-
// request(3000)({
19+
// request(3000, true)({
1720
// method: 'GET',
1821
// path: '/v1/blorp/blorp-1'
1922
// hostname: 'api.bloop.com',
2023
// }, function(err, res) {
2124
// ...
2225
// });
2326
//
24-
// request(3000)({
27+
// request(3000, true)({
2528
// method: 'POST',
2629
// path: '/v1/blorp/blorp-1'
2730
// hostname: 'api.bloop.com',
@@ -40,7 +43,7 @@ function request(timeout) {
4043

4144
callback = once(callback);
4245

43-
var req = https.request(options);
46+
var req = (secure ? https : http).request(options);
4447

4548
req.on('response', responseHandler(callback));
4649
req.on('error', errorHandler(callback));

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "button-client-node",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "node.js client for the Button Order API",
55
"main": "index.js",
66
"scripts": {

test/index-test.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var expect = require('expect.js');
4+
var nock = require('nock');
45

56
var client = require('../index');
67

@@ -20,4 +21,71 @@ describe('client', function() {
2021
expect(typeof client('sk-XXX', {}).orders).to.eql('object');
2122
});
2223

24+
describe('config', function() {
25+
before(function() {
26+
nock.disableNetConnect();
27+
});
28+
29+
after(function() {
30+
nock.enableNetConnect();
31+
});
32+
33+
it('defaults config options', function(done) {
34+
var c = client('sk-XXX').orders;
35+
var orderId = 'btnorder-XXX';
36+
var scope = nock('https://api.usebutton.com:443')
37+
.get('/v1/order/' + orderId)
38+
.reply(200, { meta: { status: 'ok' }, 'object': {} });
39+
40+
c.get(orderId, function(err) {
41+
expect(err).to.be(null);
42+
scope.done();
43+
done();
44+
}.bind(this));
45+
});
46+
47+
it('makes insecure requests', function(done) {
48+
var c = client('sk-XXX', { secure: false }).orders;
49+
var orderId = 'btnorder-XXX';
50+
var scope = nock('http://api.usebutton.com:80')
51+
.get('/v1/order/' + orderId)
52+
.reply(200, { meta: { status: 'ok' }, 'object': {} });
53+
54+
c.get(orderId, function(err) {
55+
expect(err).to.be(null);
56+
scope.done();
57+
done();
58+
}.bind(this));
59+
});
60+
61+
it('overrides the hostname', function(done) {
62+
var c = client('sk-XXX', { hostname: 'staging.usebutton.com' }).orders;
63+
var orderId = 'btnorder-XXX';
64+
var scope = nock('https://staging.usebutton.com:443')
65+
.get('/v1/order/' + orderId)
66+
.reply(200, { meta: { status: 'ok' }, 'object': {} });
67+
68+
c.get(orderId, function(err) {
69+
expect(err).to.be(null);
70+
scope.done();
71+
done();
72+
}.bind(this));
73+
});
74+
75+
it('overrides the port', function(done) {
76+
var c = client('sk-XXX', { port: 1989 }).orders;
77+
var orderId = 'btnorder-XXX';
78+
var scope = nock('https://api.usebutton.com:1989')
79+
.get('/v1/order/' + orderId)
80+
.reply(200, { meta: { status: 'ok' }, 'object': {} });
81+
82+
c.get(orderId, function(err) {
83+
expect(err).to.be(null);
84+
scope.done();
85+
done();
86+
}.bind(this));
87+
});
88+
89+
});
90+
2391
});

test/lib/merge-test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ describe('lib/#merge', function() {
2626
expect(merged).to.eql({ a: 3, b: 3, c: 4 });
2727
});
2828

29+
it('skips non-objects', function() {
30+
var merged = merge({ a : 1 }, undefined, null, 2, false, '', [0, 1, 2], { b: 3 });
31+
expect(merged).to.eql({ a: 1, b: 3 });
32+
});
33+
2934
});

test/lib/request-test.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('lib/#request', function() {
3434
});
3535

3636
beforeEach(function() {
37-
this.request = request();
37+
this.request = request(false, true);
3838
});
3939

4040
it('makes a basic GET request', function(done) {
@@ -161,7 +161,7 @@ describe('lib/#request', function() {
161161
});
162162

163163
it('handles timeout errors', function(done) {
164-
var timeoutRequest = request(10);
164+
var timeoutRequest = request(10, true);
165165
var path = '/bleep/bloop';
166166
var hostname = 'api.usebutton.com';
167167

@@ -184,7 +184,7 @@ describe('lib/#request', function() {
184184

185185
it('succeeds if faster than the timeout', function(done) {
186186
var payload = {};
187-
var timeoutRequest = request(1000);
187+
var timeoutRequest = request(1000, true);
188188
var path = '/bleep/bloop';
189189
var hostname = 'api.usebutton.com';
190190

@@ -399,4 +399,25 @@ describe('lib/#request', function() {
399399
});
400400
});
401401

402+
it('makes insecure requests', function(done) {
403+
var insecureRequest = request(false, false);
404+
var path = '/bleep/bloop';
405+
var hostname = 'api.usebutton.com';
406+
407+
var scope = nock('http://' + hostname + ':80')
408+
.get(path)
409+
.reply(200, successResponse({}));
410+
411+
insecureRequest({
412+
method: 'GET',
413+
path: path,
414+
hostname: hostname
415+
}, function(err, res) {
416+
expect(err).to.be(null);
417+
expect(res.data).to.eql({});
418+
scope.done();
419+
done();
420+
});
421+
});
422+
402423
});

test/lib/resources/orders-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('lib/resources/orders', function() {
2626
describe('#get', function() {
2727

2828
beforeEach(function() {
29-
this.orderId = 'btnorder-4c944faaaa747dcb';
29+
this.orderId = 'btnorder-XXX';
3030
this.order = { 'button_order_id': 'btnorder-XXX' };
3131
this.scope = nock('https://api.usebutton.com:443')
3232
.get('/v1/order/' + this.orderId)

0 commit comments

Comments
 (0)