Commit a6f78461 by Alex MacCaw

Remove pending API - turn Queued into an exception

parent cac6f0d1
...@@ -12,7 +12,7 @@ $ npm install clearbit ...@@ -12,7 +12,7 @@ $ npm install clearbit
``` ```
```js ```js
var clearbit = require('clearbit')('api_key'); var clearbit = require('clearbit')('api_key');
// or // or
var Client = require('clearbit').Client; var Client = require('clearbit').Client;
var clearbit = new Client({key: 'api_key'}); var clearbit = new Client({key: 'api_key'});
``` ```
...@@ -26,13 +26,13 @@ var clearbit = new Client({key: 'api_key'}); ...@@ -26,13 +26,13 @@ var clearbit = new Client({key: 'api_key'});
* `webhook_id` *String*: Custom identifier for the webhook request * `webhook_id` *String*: Custom identifier for the webhook request
* `subscribe` *Boolean*: Set to `true` to subscribe to the changes * `subscribe` *Boolean*: Set to `true` to subscribe to the changes
* `company` *Boolean*: Set to `true` to include a company lookup on the email’s domain name in the response * `company` *Boolean*: Set to `true` to include a company lookup on the email’s domain name in the response
* `stream` *Boolean*: Set to `true` to use the [streaming API](https://clearbit.co/docs?shell#streaming) instead of webhooks * `stream` *Boolean*: Set to `true` to use the [streaming API](https://clearbit.co/docs?shell#streaming) instead of webhooks
```js ```js
var Person = clearbit.Person; var Person = clearbit.Person;
Person.find({email: 'email@domain.com'}) Person.find({email: 'email@domain.com'})
.then(function (person) { .then(function (person) {
if (!person.pending()) { if (!person.isPending()) {
console.log('Name: ', person.name.fullName); console.log('Name: ', person.name.fullName);
} }
}) })
...@@ -44,21 +44,18 @@ Person.find({email: 'email@domain.com'}) ...@@ -44,21 +44,18 @@ Person.find({email: 'email@domain.com'})
}); });
``` ```
#### `person.pending()` -> `Boolean`
If Clearbit responds with a `202` status indicating that lookup has been queued, `person.pending` returns `true`.
### Company ### Company
#### `Company.find(options)` -> `Promise` #### `Company.find(options)` -> `Promise`
* `domain` *String*: The company domain to look up **(required)** * `domain` *String*: The company domain to look up **(required)**
* `webhook_id` *String*: Custom identifier for the webhook request * `webhook_id` *String*: Custom identifier for the webhook request
* `stream` *Boolean*: Set to `true` to use the [streaming API](https://clearbit.co/docs?shell#streaming) instead of webhooks * `stream` *Boolean*: Set to `true` to use the [streaming API](https://clearbit.co/docs?shell#streaming) instead of webhooks
```js ```js
var Company = clearbit.Company; var Company = clearbit.Company;
Company.find({domain: 'www.uber.com'}) Company.find({domain: 'www.uber.com'})
.then(function (company) { .then(function (company) {
if (!company.pending()) { if (!company.isPending()) {
console.log('Name: ', company.name); console.log('Name: ', company.name);
} }
}) })
...@@ -70,8 +67,18 @@ Company.find({domain: 'www.uber.com'}) ...@@ -70,8 +67,18 @@ Company.find({domain: 'www.uber.com'})
}); });
``` ```
#### `company.pending()` -> `Boolean` ### Queued Handling
If Clearbit responds with a `202` status indicating that lookup has been queued, `company.pending` returns `true`.
If Clearbit responds with a `202` status indicating that lookup has been queued, then a `QueuedError` will be thrown. You can catch this like so:
```js
Person.find({email: 'notqueued@example.com'})
.catch(Person.QueuedError, function () {
// Record has been queued
})
```
If long-lived requests are not a problem for you you can avoid queuing errors by using our streaming API.
### Error Handling ### Error Handling
Lookups return [Bluebird](https://github.com/petkaantonov/bluebird) promises. Any status code >=400 will trigger an error, including lookups than do not return a result. You can easily filter out unknown records from true errors using [Bluebird's error class matching](https://github.com/petkaantonov/bluebird/blob/master/API.md#catchfunction-errorclassfunction-predicate-function-handler---promise): Lookups return [Bluebird](https://github.com/petkaantonov/bluebird) promises. Any status code >=400 will trigger an error, including lookups than do not return a result. You can easily filter out unknown records from true errors using [Bluebird's error class matching](https://github.com/petkaantonov/bluebird/blob/master/API.md#catchfunction-errorclassfunction-predicate-function-handler---promise):
......
...@@ -17,6 +17,7 @@ function ClearbitClient (config) { ...@@ -17,6 +17,7 @@ function ClearbitClient (config) {
this.Person = require('./person')(this); this.Person = require('./person')(this);
this.Company = require('./company')(this); this.Company = require('./company')(this);
this.PersonCompany = require('./person_company')(this);
} }
var base = 'https://%s%s.clearbit.co/v%s'; var base = 'https://%s%s.clearbit.co/v%s';
...@@ -66,7 +67,7 @@ ClearbitClient.prototype.request = function (options) { ...@@ -66,7 +67,7 @@ ClearbitClient.prototype.request = function (options) {
) )
.bind(this) .bind(this)
.spread(function (response, body) { .spread(function (response, body) {
if (response.statusCode >= 400) { if (response.statusCode == 202 || response.statusCode >= 400) {
var message = body.error ? body.error.message : http.STATUS_CODES[response.statusCode] || 'Unknown'; var message = body.error ? body.error.message : http.STATUS_CODES[response.statusCode] || 'Unknown';
throw _.extend(new this.ClearbitError(message), { throw _.extend(new this.ClearbitError(message), {
type: body.error ? body.error.type : 'unknown', type: body.error ? body.error.type : 'unknown',
......
...@@ -10,8 +10,6 @@ module.exports = function (client) { ...@@ -10,8 +10,6 @@ module.exports = function (client) {
_.extend(this, data); _.extend(this, data);
} }
Company.prototype.pending = utils.pending;
Company.find = Promise.method(function (options) { Company.find = Promise.method(function (options) {
assert(options && options.domain, 'A domain must be provided'); assert(options && options.domain, 'A domain must be provided');
return this.client.request(_.extend({ return this.client.request(_.extend({
...@@ -20,6 +18,9 @@ module.exports = function (client) { ...@@ -20,6 +18,9 @@ module.exports = function (client) {
}, options)) }, options))
.bind(this) .bind(this)
.then(utils.cast) .then(utils.cast)
.catch(utils.isQueued, function () {
throw new this.QueuedError('Company lookup queued');
})
.catch(utils.isUnknownRecord, function () { .catch(utils.isUnknownRecord, function () {
throw new this.NotFoundError('Company not found'); throw new this.NotFoundError('Company not found');
}); });
...@@ -27,6 +28,7 @@ module.exports = function (client) { ...@@ -27,6 +28,7 @@ module.exports = function (client) {
Company.prototype.client = Company.client = client; Company.prototype.client = Company.client = client;
Company.NotFoundError = utils.NotFoundError; Company.NotFoundError = utils.NotFoundError;
Company.QueuedError = utils.QueuedError;
return Company; return Company;
}; };
...@@ -10,8 +10,6 @@ module.exports = function (client) { ...@@ -10,8 +10,6 @@ module.exports = function (client) {
_.extend(this, data); _.extend(this, data);
} }
Person.prototype.pending = utils.pending;
Person.find = Promise.method(function (options) { Person.find = Promise.method(function (options) {
assert(options && options.email, 'An email must be provided'); assert(options && options.email, 'An email must be provided');
return this.client.request(_.extend({ return this.client.request(_.extend({
...@@ -21,6 +19,9 @@ module.exports = function (client) { ...@@ -21,6 +19,9 @@ module.exports = function (client) {
}, options)) }, options))
.bind(this) .bind(this)
.then(utils.cast) .then(utils.cast)
.catch(utils.isQueued, function () {
throw new this.QueuedError('Person lookup queued');
})
.catch(utils.isUnknownRecord, function () { .catch(utils.isUnknownRecord, function () {
throw new this.NotFoundError('Person not found'); throw new this.NotFoundError('Person not found');
}); });
...@@ -28,6 +29,7 @@ module.exports = function (client) { ...@@ -28,6 +29,7 @@ module.exports = function (client) {
Person.prototype.client = Person.client = client; Person.prototype.client = Person.client = client;
Person.NotFoundError = utils.NotFoundError; Person.NotFoundError = utils.NotFoundError;
Person.QueuedError = utils.QueuedError;
return Person; return Person;
}; };
...@@ -10,8 +10,6 @@ module.exports = function (client) { ...@@ -10,8 +10,6 @@ module.exports = function (client) {
_.extend(this, data); _.extend(this, data);
} }
PersonCompany.prototype.pending = utils.pending;
PersonCompany.find = Promise.method(function (options) { PersonCompany.find = Promise.method(function (options) {
assert(options && options.email, 'An email must be provided'); assert(options && options.email, 'An email must be provided');
return this.client.request(_.extend({ return this.client.request(_.extend({
...@@ -21,6 +19,9 @@ module.exports = function (client) { ...@@ -21,6 +19,9 @@ module.exports = function (client) {
}, options)) }, options))
.bind(this) .bind(this)
.then(utils.cast) .then(utils.cast)
.catch(utils.isQueued, function () {
throw new this.QueuedError('PersonCompany lookup queued');
})
.catch(utils.isUnknownRecord, function () { .catch(utils.isUnknownRecord, function () {
throw new this.NotFoundError('PersonCompany not found'); throw new this.NotFoundError('PersonCompany not found');
}); });
...@@ -28,6 +29,7 @@ module.exports = function (client) { ...@@ -28,6 +29,7 @@ module.exports = function (client) {
PersonCompany.prototype.client = PersonCompany.client = client; PersonCompany.prototype.client = PersonCompany.client = client;
PersonCompany.NotFoundError = utils.NotFoundError; PersonCompany.NotFoundError = utils.NotFoundError;
PersonCompany.QueuedError = utils.QueuedError;
return PersonCompany; return PersonCompany;
}; };
...@@ -6,12 +6,13 @@ exports.cast = function (data) { ...@@ -6,12 +6,13 @@ exports.cast = function (data) {
return new this(data); return new this(data);
}; };
exports.pending = function () {
return !this.id;
};
exports.NotFoundError = createError('NotFoundError'); exports.NotFoundError = createError('NotFoundError');
exports.QueuedError = createError('QueuedError');
exports.isUnknownRecord = function (err) { exports.isUnknownRecord = function (err) {
return err.type === 'unknown_record'; return err.type === 'unknown_record';
}; };
exports.isQueued = function (err) {
return err.type === 'queued';
};
\ No newline at end of file
...@@ -80,7 +80,7 @@ describe('Client', function () { ...@@ -80,7 +80,7 @@ describe('Client', function () {
it('sends a get request to the specified endpoint', function () { it('sends a get request to the specified endpoint', function () {
mock mock
.get('/v1/people/email/bvdrucker@gmail.com') .get('/v1/people/email/bvdrucker@gmail.com')
.reply(202); .reply(200);
return client.request({ return client.request({
api: 'person', api: 'person',
path: '/people/email/bvdrucker@gmail.com' path: '/people/email/bvdrucker@gmail.com'
...@@ -90,7 +90,7 @@ describe('Client', function () { ...@@ -90,7 +90,7 @@ describe('Client', function () {
it('can generate a qs', function () { it('can generate a qs', function () {
mock mock
.get('/v1/people/email/bvdrucker@gmail.com?webhook_id=123') .get('/v1/people/email/bvdrucker@gmail.com?webhook_id=123')
.reply(202); .reply(200);
return client.request({ return client.request({
api: 'person', api: 'person',
path: '/people/email/bvdrucker@gmail.com', path: '/people/email/bvdrucker@gmail.com',
...@@ -119,7 +119,7 @@ describe('Client', function () { ...@@ -119,7 +119,7 @@ describe('Client', function () {
mock mock
.get('/v1/people/email/bvdrucker@gmail.com') .get('/v1/people/email/bvdrucker@gmail.com')
.matchHeader('Authorization', 'Basic azo=') .matchHeader('Authorization', 'Basic azo=')
.reply(202); .reply(200);
return client.request({ return client.request({
api: 'person', api: 'person',
path: '/people/email/bvdrucker@gmail.com' path: '/people/email/bvdrucker@gmail.com'
...@@ -130,7 +130,7 @@ describe('Client', function () { ...@@ -130,7 +130,7 @@ describe('Client', function () {
mock mock
.get('/v1/people/email/bvdrucker@gmail.com') .get('/v1/people/email/bvdrucker@gmail.com')
.matchHeader('User-Agent', 'ClearbitNode/v' + pkg.version) .matchHeader('User-Agent', 'ClearbitNode/v' + pkg.version)
.reply(202); .reply(200);
return client.request({ return client.request({
api: 'person', api: 'person',
path: '/people/email/bvdrucker@gmail.com' path: '/people/email/bvdrucker@gmail.com'
......
...@@ -15,17 +15,6 @@ describe('Company', function () { ...@@ -15,17 +15,6 @@ describe('Company', function () {
mock.done(); mock.done();
}); });
describe('#pending', function () {
it('identifies whether the company has an id', function () {
var company = new Company();
expect(company.pending()).to.be.true;
company.id = 'foo';
expect(company.pending()).to.be.false;
});
});
describe('Company#find', function () { describe('Company#find', function () {
var company = require('./fixtures/company'); var company = require('./fixtures/company');
...@@ -42,14 +31,17 @@ describe('Company', function () { ...@@ -42,14 +31,17 @@ describe('Company', function () {
}); });
}); });
it('can handle pending requests', function () { it('can handle queued requests', function () {
mock mock
.get('/v1/companies/domain/uber.com') .get('/v1/companies/domain/uber.com')
.reply(202); .reply(202, {
return Company.find({domain: 'uber.com'}) error: {
.then(function (company) { type: 'queued'
expect(company.pending()).to.be.true; }
}); });
return Company.find({domain: 'uber.com'})
.to.be.rejectedWith(Company.QueuedError);
}); });
it('can handle unknown records', function () { it('can handle unknown records', function () {
......
...@@ -15,17 +15,6 @@ describe('Person', function () { ...@@ -15,17 +15,6 @@ describe('Person', function () {
mock.done(); mock.done();
}); });
describe('#pending', function () {
it('identifies whether the person has an id', function () {
var person = new Person();
expect(person.pending()).to.be.true;
person.id = 'foo';
expect(person.pending()).to.be.false;
});
});
describe('Person#find', function () { describe('Person#find', function () {
var alex = require('./fixtures/person'); var alex = require('./fixtures/person');
...@@ -56,14 +45,16 @@ describe('Person', function () { ...@@ -56,14 +45,16 @@ describe('Person', function () {
return Person.find({email: 'alex@alexmaccaw.com', company: false}); return Person.find({email: 'alex@alexmaccaw.com', company: false});
}); });
it('can handle pending requests', function () { it('can handle queued requests', function () {
mock mock
.get('/v1/people/email/alex@alexmaccaw.com') .get('/v1/people/email/alex@alexmaccaw.com')
.reply(202); .reply(202, {
return Person.find({email: 'alex@alexmaccaw.com'}) error: {
.then(function (person) { type: 'queued'
expect(person.pending()).to.be.true; }
}); });
return Person.find({email: 'alex@alexmaccaw.com'})
.to.be.rejectedWith(Company.QueuedError);
}); });
it('can handle unknown records', function () { it('can handle unknown records', function () {
......
...@@ -15,17 +15,6 @@ describe('PersonCompany', function () { ...@@ -15,17 +15,6 @@ describe('PersonCompany', function () {
mock.done(); mock.done();
}); });
describe('#pending', function () {
it('identifies whether the person has an id', function () {
var person = new PersonCompany();
expect(person.pending()).to.be.true;
person.id = 'foo';
expect(person.pending()).to.be.false;
});
});
describe('PersonCompany#find', function () { describe('PersonCompany#find', function () {
var alex = require('./fixtures/person'); var alex = require('./fixtures/person');
...@@ -42,14 +31,16 @@ describe('PersonCompany', function () { ...@@ -42,14 +31,16 @@ describe('PersonCompany', function () {
}); });
}); });
it('can handle pending requests', function () { it('can handle queued requests', function () {
mock mock
.get('/v1/combined/email/alex@alexmaccaw.com') .get('/v1/combined/email/alex@alexmaccaw.com')
.reply(202); .reply(202, {
return PersonCompany.find({email: 'alex@alexmaccaw.com'}) error: {
.then(function (person) { type: 'queued'
expect(person.pending()).to.be.true; }
}); });
return PersonCompany.find({email: 'alex@alexmaccaw.com'})
.to.be.rejectedWith(PersonCompany.QueuedError);
}); });
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment