Skip to content

Commit 3d10227

Browse files
authored
Merge pull request #17 from button/mikey/add-response-to-errors
Include http response in errors; v2.4.0.
2 parents 69b00b2 + 3278df3 commit 3d10227

File tree

5 files changed

+50
-9
lines changed

5 files changed

+50
-9
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2.4.0 June 12, 2017
2+
- Request errors now include the `response` object.
3+
14
2.3.0 January 6, 2017
25
- Add `merchants` resource
36
+ `merchants#all`

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ client.orders.get('btnorder-XXX', function(err, res) {
5858

5959
All callbacks will be invoked with two arguments. `err` will be an `Error` object if an error occurred and `null` otherwise. `res` will be the API response if the request succeeded or `null` otherwise.
6060

61+
If an `Error` is returned after the client receives a response, such as for an upstream HTTP error, the `Error.response` property will be set to the NodeJS `response` object.
62+
6163
#### Promise
6264

6365
`button-client-node` supports a promise interface. To make a promise-based request, supply a function that accepts a single resolver function and returns a new promise on the `promise` key of your `config`. Additionally, you must omit the callback from your API function call.

lib/request.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,34 +72,44 @@ function responseHandler(callback) {
7272
res.on('end', function onEnd() {
7373
if (!rawResponse) {
7474
return callback(
75-
new Error('Client received an empty response from the server'),
75+
formatError('Client received an empty response from the server', res),
7676
null
7777
);
7878
}
7979

8080
try {
8181
var response = JSON.parse(rawResponse);
8282
} catch (e) {
83-
return callback(new Error('Error parsing response as JSON: ' + rawResponse), null);
83+
return callback(
84+
formatError('Error parsing response as JSON: ' + rawResponse, res),
85+
null
86+
);
8487
}
8588

8689
if (typeof response.meta !== 'object' || !response.meta.status) {
87-
return callback(new Error('Invalid response: ' + rawResponse), null);
90+
return callback(
91+
formatError('Invalid response: ' + rawResponse, res),
92+
null
93+
);
8894
}
8995

9096
var status = response.meta.status;
9197

9298
if (status === 'ok') {
9399
return callback(null, formatResponse(response));
94-
} else if (status === 'error') {
100+
}
101+
102+
var msg;
103+
if (status === 'error') {
95104
if (typeof response.error !== 'object' || !response.error.message) {
96-
return callback(new Error('Invalid response: ' + rawResponse), null);
105+
msg = 'Invalid response: ' + rawResponse;
106+
} else {
107+
msg = response.error.message;
97108
}
98-
99-
return callback(new Error(response.error.message), null);
100109
} else {
101-
return callback(new Error('Unknown status: ' + status), null);
110+
msg = 'Unknown status: ' + status;
102111
}
112+
return callback(formatError(msg, res), null);
103113
});
104114
};
105115
}
@@ -127,6 +137,12 @@ function formatResponse(response) {
127137
};
128138
}
129139

140+
function formatError(message, response) {
141+
var err = new Error(message);
142+
err.response = response;
143+
return err;
144+
}
145+
130146
function formatCursor(url) {
131147
if (typeof url === 'string') {
132148
var parsed = parse(url, true);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@button/button-client-node",
3-
"version": "2.3.0",
3+
"version": "2.4.0",
44
"description": "node.js client for the Button Order API",
55
"repository": {
66
"type": "git",

test/lib/request-test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ describe('lib/#request', function() {
133133
hostname: hostname
134134
}, function(err, res) {
135135
expect(err.message).to.be(error);
136+
expect(err.response).to.be.ok();
137+
expect(err.response.statusCode).to.eql(404);
136138
expect(res).to.eql(null);
137139
scope.done();
138140
done();
@@ -154,6 +156,7 @@ describe('lib/#request', function() {
154156
hostname: hostname
155157
}, function(err, res) {
156158
expect(err.message).to.be(error);
159+
expect(err.response).to.not.be.ok();
157160
expect(res).to.eql(null);
158161
scope.done();
159162
done();
@@ -176,6 +179,7 @@ describe('lib/#request', function() {
176179
hostname: hostname
177180
}, function(err, res) {
178181
expect(err.message).to.be('Request timed out');
182+
expect(err.response).to.not.be.ok();
179183
expect(res).to.eql(null);
180184
scope.done();
181185
done();
@@ -219,6 +223,8 @@ describe('lib/#request', function() {
219223
hostname: hostname
220224
}, function(err, res) {
221225
expect(err.message).to.be('Error parsing response as JSON: not json');
226+
expect(err.response).to.be.ok();
227+
expect(err.response.statusCode).to.eql(200);
222228
expect(res).to.eql(null);
223229
scope.done();
224230
done();
@@ -239,6 +245,8 @@ describe('lib/#request', function() {
239245
hostname: hostname
240246
}, function(err, res) {
241247
expect(err.message).to.be('Client received an empty response from the server');
248+
expect(err.response).to.be.ok();
249+
expect(err.response.statusCode).to.eql(200);
242250
expect(res).to.eql(null);
243251
scope.done();
244252
done();
@@ -259,6 +267,8 @@ describe('lib/#request', function() {
259267
hostname: hostname
260268
}, function(err, res) {
261269
expect(err.message).to.be('Unknown status: ???');
270+
expect(err.response).to.be.ok();
271+
expect(err.response.statusCode).to.eql(200);
262272
expect(res).to.eql(null);
263273
scope.done();
264274
done();
@@ -279,6 +289,8 @@ describe('lib/#request', function() {
279289
hostname: hostname
280290
}, function(err, res) {
281291
expect(err.message).to.be('Unknown status: ???');
292+
expect(err.response).to.be.ok();
293+
expect(err.response.statusCode).to.eql(200);
282294
expect(res).to.eql(null);
283295
scope.done();
284296
done();
@@ -299,6 +311,8 @@ describe('lib/#request', function() {
299311
hostname: hostname
300312
}, function(err, res) {
301313
expect(err.message).to.be('Invalid response: {}');
314+
expect(err.response).to.be.ok();
315+
expect(err.response.statusCode).to.eql(200);
302316
expect(res).to.eql(null);
303317
scope.done();
304318
done();
@@ -319,6 +333,8 @@ describe('lib/#request', function() {
319333
hostname: hostname
320334
}, function(err, res) {
321335
expect(err.message).to.be('Invalid response: {"meta":"wat"}');
336+
expect(err.response).to.be.ok();
337+
expect(err.response.statusCode).to.eql(200);
322338
expect(res).to.eql(null);
323339
scope.done();
324340
done();
@@ -339,6 +355,8 @@ describe('lib/#request', function() {
339355
hostname: hostname
340356
}, function(err, res) {
341357
expect(err.message).to.be('Invalid response: {"meta":{"status":"error"}}');
358+
expect(err.response).to.be.ok();
359+
expect(err.response.statusCode).to.eql(200);
342360
expect(res).to.eql(null);
343361
scope.done();
344362
done();
@@ -359,6 +377,8 @@ describe('lib/#request', function() {
359377
hostname: hostname
360378
}, function(err, res) {
361379
expect(err.message).to.be('Invalid response: {"meta":{"status":"error"},"error":"wat"}');
380+
expect(err.response).to.be.ok();
381+
expect(err.response.statusCode).to.eql(200);
362382
expect(res).to.eql(null);
363383
scope.done();
364384
done();

0 commit comments

Comments
 (0)