Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
2.4.0 June 12, 2017
- Request errors now include the `response` object.

2.3.0 January 6, 2017
- Add `merchants` resource
+ `merchants#all`
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ client.orders.get('btnorder-XXX', function(err, res) {

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.

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.

#### Promise

`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.
Expand Down
32 changes: 24 additions & 8 deletions lib/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,34 +72,44 @@ function responseHandler(callback) {
res.on('end', function onEnd() {
if (!rawResponse) {
return callback(
new Error('Client received an empty response from the server'),
formatError('Client received an empty response from the server', res),
null
);
}

try {
var response = JSON.parse(rawResponse);
} catch (e) {
return callback(new Error('Error parsing response as JSON: ' + rawResponse), null);
return callback(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: drop null and the trailing ) onto new lines, like on line 75. Optional, because I haven't found an eslint rule for it yet!

formatError('Error parsing response as JSON: ' + rawResponse, res),
null
);
}

if (typeof response.meta !== 'object' || !response.meta.status) {
return callback(new Error('Invalid response: ' + rawResponse), null);
return callback(
formatError('Invalid response: ' + rawResponse, res),
null
);
}

var status = response.meta.status;

if (status === 'ok') {
return callback(null, formatResponse(response));
} else if (status === 'error') {
}

var msg;
if (status === 'error') {
if (typeof response.error !== 'object' || !response.error.message) {
return callback(new Error('Invalid response: ' + rawResponse), null);
msg = 'Invalid response: ' + rawResponse;
} else {
msg = response.error.message;
}

return callback(new Error(response.error.message), null);
} else {
return callback(new Error('Unknown status: ' + status), null);
msg = 'Unknown status: ' + status;
}
return callback(formatError(msg, res), null);
});
};
}
Expand Down Expand Up @@ -127,6 +137,12 @@ function formatResponse(response) {
};
}

function formatError(message, response) {
var err = new Error(message);
err.response = response;
return err;
}

function formatCursor(url) {
if (typeof url === 'string') {
var parsed = parse(url, true);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@button/button-client-node",
"version": "2.3.0",
"version": "2.4.0",
"description": "node.js client for the Button Order API",
"repository": {
"type": "git",
Expand Down
20 changes: 20 additions & 0 deletions test/lib/request-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be(error);
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(404);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -154,6 +156,7 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be(error);
expect(err.response).to.not.be.ok();
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -176,6 +179,7 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Request timed out');
expect(err.response).to.not.be.ok();
expect(res).to.eql(null);
scope.done();
done();
Expand Down Expand Up @@ -219,6 +223,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Error parsing response as JSON: not json');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -239,6 +245,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Client received an empty response from the server');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -259,6 +267,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Unknown status: ???');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -279,6 +289,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Unknown status: ???');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -299,6 +311,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Invalid response: {}');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -319,6 +333,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Invalid response: {"meta":"wat"}');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -339,6 +355,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Invalid response: {"meta":{"status":"error"}}');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand All @@ -359,6 +377,8 @@ describe('lib/#request', function() {
hostname: hostname
}, function(err, res) {
expect(err.message).to.be('Invalid response: {"meta":{"status":"error"},"error":"wat"}');
expect(err.response).to.be.ok();
expect(err.response.statusCode).to.eql(200);
expect(res).to.eql(null);
scope.done();
done();
Expand Down