Skip to content

Commit

Permalink
Parse errors from profile endpoint.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredhanson committed Aug 15, 2013
1 parent a80d40b commit a4f3ec3
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 4 deletions.
34 changes: 34 additions & 0 deletions lib/errors/facebookgraphapierror.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* `FacebookGraphAPIError` error.
*
* References:
* - https://developers.facebook.com/docs/reference/api/errors/
*
* @constructor
* @param {String} [message]
* @param {String} [type]
* @param {Number} [code]
* @param {Number} [subcode]
* @api public
*/
function FacebookGraphAPIError(message, type, code, subcode) {
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.name = 'FacebookGraphAPIError';
this.message = message;
this.type = type;
this.code = code;
this.subcode = subcode;
this.status = 500;
}

/**
* Inherit from `Error`.
*/
FacebookGraphAPIError.prototype.__proto__ = Error.prototype;


/**
* Expose `FacebookGraphAPIError`.
*/
module.exports = FacebookGraphAPIError;
19 changes: 15 additions & 4 deletions lib/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ var parse = require('./profile').parse
, OAuth2Strategy = require('passport-oauth2')
, InternalOAuthError = require('passport-oauth2').InternalOAuthError
, FacebookAuthorizationError = require('./errors/facebookauthorizationerror')
, FacebookTokenError = require('./errors/facebooktokenerror');
, FacebookTokenError = require('./errors/facebooktokenerror')
, FacebookGraphAPIError = require('./errors/facebookgraphapierror');


/**
Expand Down Expand Up @@ -137,7 +138,17 @@ Strategy.prototype.userProfile = function(accessToken, done) {
}

this._oauth2.get(url, accessToken, function (err, body, res) {
if (err) { return done(new InternalOAuthError('Failed to fetch user profile', err)); }
if (err) {
if (err.data) {
try {
var json = JSON.parse(err.data);
if (json.error && typeof json.error == 'object') {
return done(new FacebookGraphAPIError(json.error.message, json.error.type, json.error.code, json.error.error_subcode));
}
} catch (_) {}
}
return done(new InternalOAuthError('Failed to fetch user profile', err));
}

try {
var json = JSON.parse(body);
Expand All @@ -148,8 +159,8 @@ Strategy.prototype.userProfile = function(accessToken, done) {
profile._json = json;

done(null, profile);
} catch(e) {
done(e);
} catch (ex) {
done(new Error('Failed to parse user profile'));
}
});
};
Expand Down
105 changes: 105 additions & 0 deletions test/strategy.profile.error.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
var FacebookStrategy = require('../lib/strategy');


describe('Strategy#userProfile', function() {

describe('handling API errors', function() {
var strategy = new FacebookStrategy({
clientID: 'ABC123',
clientSecret: 'secret'
},
function() {});

// mock
strategy._oauth2.get = function(url, accessToken, callback) {
if (url != 'https://graph.facebook.com/me') { return callback(new Error('wrong url argument')); }
if (accessToken != 'token') { return callback(new Error('wrong token argument')); }

var body = '{"error":{"message":"Invalid OAuth access token.","type":"OAuthException","code":190}}';

callback({ statusCode: 401, data: body });
}

var err, profile;
before(function(done) {
strategy.userProfile('token', function(e, p) {
err = e;
profile = p;
done();
});
});

it('should error', function() {
expect(err).to.be.an.instanceOf(Error);
expect(err.constructor.name).to.equal('FacebookGraphAPIError');
expect(err.message).to.equal('Invalid OAuth access token.');
expect(err.type).to.equal('OAuthException');
expect(err.code).to.equal(190);
});
});

describe('handling internal OAuth errors', function() {
var strategy = new FacebookStrategy({
clientID: 'ABC123',
clientSecret: 'secret'
},
function() {});

// mock
strategy._oauth2.get = function(url, accessToken, callback) {
if (url != 'https://graph.facebook.com/me') { return callback(new Error('wrong url argument')); }
if (accessToken != 'token') { return callback(new Error('wrong token argument')); }

var body = '{"error":{"message":"Invalid OAuth access token.","type":"OAuthException","code":190}}';

callback({ statusCode: 401, x__data: body });
}

var err, profile;
before(function(done) {
strategy.userProfile('token', function(e, p) {
err = e;
profile = p;
done();
});
});

it('should error', function() {
expect(err).to.be.an.instanceOf(Error);
expect(err.constructor.name).to.equal('InternalOAuthError');
expect(err.message).to.equal('Failed to fetch user profile');
});
});

describe('handling malformed responses', function() {
var strategy = new FacebookStrategy({
clientID: 'ABC123',
clientSecret: 'secret'
},
function() {});

// mock
strategy._oauth2.get = function(url, accessToken, callback) {
if (url != 'https://graph.facebook.com/me') { return callback(new Error('wrong url argument')); }
if (accessToken != 'token') { return callback(new Error('wrong token argument')); }

var body = 'Hello, world.';
callback(null, body, undefined);
}

var err, profile;
before(function(done) {
strategy.userProfile('token', function(e, p) {
err = e;
profile = p;
done();
});
});

it('should error', function() {
expect(err).to.be.an.instanceOf(Error);
expect(err.message).to.equal('Failed to parse user profile');
});
});

});

0 comments on commit a4f3ec3

Please sign in to comment.