Skip to content
This repository has been archived by the owner on Oct 19, 2023. It is now read-only.

Commit

Permalink
Merge pull request #152 from AustinLeeGordon/master
Browse files Browse the repository at this point in the history
Add option to ignore limit check, use headers for limit check
  • Loading branch information
pcothenet authored Feb 9, 2019
2 parents 169e0f5 + 456627b commit bcc85f5
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 64 deletions.
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.codeclimate.yml
.editorconfig
.env.template
.eslintrc.js
.prettierrc
.travis.yml
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"singleQuote": true,
"semi": false,
"printWidth": 80,
"trailingComma": "all",
"trailingComma": "es5",
"endOfLine": "crlf"
}
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ npm install hubspot

```javascript
const Hubspot = require('hubspot')
const hubspot = new Hubspot({ apiKey: 'abc' })
const hubspot = new Hubspot({
apiKey: 'abc',
checkLimit: false // (Optional) Specify whether or not to check the API limit on each call. Default: true
})
```

You can also authenticate via token:
Expand All @@ -27,7 +30,7 @@ You can also authenticate via token:
const hubspot = new Hubspot({ accessToken: 'abc' })
```

To change the base url
To change the base url:

```javascript
const hubspot = new Hubspot({ accessToken: 'abc', baseUrl: 'https://some-url' })
Expand Down Expand Up @@ -75,16 +78,15 @@ hubspot.contacts
## {EXAMPLE} Create Contact

```javascript
const contactObject = {
"properties":
[
{ "property": "firstname","value": yourvalue },
{ "property": "lastname", "value": yourvalue }
]
};
const contactObj = {
"properties": [
{ "property": "firstname","value": yourvalue },
{ "property": "lastname", "value": yourvalue }
]
};

const hubspot = new Hubspot({ apiKey: YOUR API KEY });
const hubspotContact = await hubspot.contacts.create(contactObj);
const hubspot = new Hubspot({ apiKey: YOUR_API_KEY });
const hubspotContact = await hubspot.contacts.create(contactObj);
```

## {EXAMPLE} If you need to insert multiple values
Expand Down Expand Up @@ -372,9 +374,9 @@ return hubspot.oauth.getAccessToken(params).then(...)

You may use this library in your Typescript project via:

```
```typescript
import Hubspot from 'hubspot';
const hubspot = new Hubspot({ apiKey: 'key' });
const hubspot = new Hubspot({ apiKey: YOUR_API_KEY });
```

## License
Expand Down
11 changes: 5 additions & 6 deletions contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
Before submitting a pull request, please make sure the following is done:

1. Fork the repository and create your branch from master.
1. Run `npm build`. This will:
a. Run `npm install` in the repository root.
a. Ensure the test suite passes with`npm test`.
a. Format your code with prettier and eslint using `npm run lint`.

1. If you’ve fixed a bug or added code that should be tested, add tests!
2. Run `npm build`. This will:
1. Run `npm install` in the repository root.
2. Ensure the test suite passes with `npm test`.
3. Format your code with prettier and eslint using `npm run lint`.
3. If you’ve fixed a bug or added code that should be tested, add tests!

Tip: `npm run mocha -- --grep "test name"` is helpful in development.
74 changes: 51 additions & 23 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const EventEmitter = require('events').EventEmitter
const Bottleneck = require('bottleneck')
const limiter = new Bottleneck({
maxConcurrent: 9,
minTime: 1000,
minTime: 1000 / 8,
})

const debug = require('debug')('hubspot:client')
Expand All @@ -47,6 +47,8 @@ class Client extends EventEmitter {
debug('apiCall', _.pick(params, ['method', 'url']))
this.apiCalls += 1
})
this.checkLimit =
options.checkLimit !== undefined ? options.checkLimit : true

this.broadcasts = new Broadcast(this)
this.campaigns = new Campaign(this)
Expand Down Expand Up @@ -108,6 +110,7 @@ class Client extends EventEmitter {
params.auth = this.auth
}
params.json = true
params.resolveWithFullResponse = true

params.url = this.baseUrl + params.path
delete params.path
Expand All @@ -121,34 +124,59 @@ class Client extends EventEmitter {

return this.checkApiLimit(params).then(() => {
this.emit('apiCall', params)
return limiter.schedule(() => request(params)) // limit the number of concurrent requests
return limiter.schedule(() =>
request(params)
.then(res => {
this.updateApiLimit(res)
return res
})
.then(res => res.body)
) // limit the number of concurrent requests
})
}

checkApiLimit(params) {
if (this.auth) {
// don't check the api limit for the api call
return Promise.resolve()
}
if (/integrations\/v1\/limit|oauth/.test(params.url)) {
// don't check the api limit for the api call
return Promise.resolve()
updateApiLimit(res) {
const { headers } = res
if (this.usageLimit === undefined) {
this.usageLimit = headers['x-hubspot-ratelimit-daily']
}
if (this.maxUsePercent === 0) {
// if maxUsePercent set to 0, do not check for the API limit (use at your own risk)
return Promise.resolve()
if (this.usageLimit !== undefined) {
this.currentUsage =
this.usageLimit - headers['x-hubspot-ratelimit-daily-remaining']
}
return this.getApiLimit().then(results => {
const { usageLimit = 40000, currentUsage = 0 } = results
const usagePercent = (100.0 * currentUsage) / usageLimit
debug('usagePercent', usagePercent, 'apiCalls', this.apiCalls)
if (usagePercent > this.maxUsePercent) {
const err = new Error('Too close to the API limit')
err.usageLimit = usageLimit
err.currentUsage = currentUsage
err.usagePercent = usagePercent
throw err
return Promise.resolve()
}

checkApiLimit(params) {
return new Promise((resolve, reject) => {
if (this.auth) {
// don't check the api limit for the api call
resolve()
}
if (/integrations\/v1\/limit|oauth/.test(params.url)) {
// don't check the api limit for the api call
resolve()
}
if (!this.checkLimit) {
// don't check the api limit for the api call
resolve()
}
if (this.maxUsePercent === 0) {
// if maxUsePercent set to 0, do not check for the API limit (use at your own risk)
resolve()
}
if (this.currentUsage !== undefined) {
const usagePercent = (100.0 * this.currentUsage) / this.usageLimit
debug('usagePercent', usagePercent, 'apiCalls', this.apiCalls)
if (usagePercent > this.maxUsePercent) {
const err = new Error('Too close to the API limit')
err.usageLimit = this.usageLimit
err.currentUsage = this.currentUsage
err.usagePercent = usagePercent
reject(err)
}
}
resolve()
})
}

Expand Down
2 changes: 1 addition & 1 deletion lib/company.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Company {
addContactToCompany(data) {
if (!data || !data.companyId || !data.contactVid) {
return Promise.reject(
new Error('companyId and contactVid params must be provided'),
new Error('companyId and contactVid params must be provided')
)
}

Expand Down
2 changes: 1 addition & 1 deletion lib/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class List {
}
if (!contactBody) {
return Promise.reject(
new Error('contactBody parameter must be provided.'),
new Error('contactBody parameter must be provided.')
)
}

Expand Down
4 changes: 2 additions & 2 deletions lib/typescript/deal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ declare class Deal {
associate(
id: number,
objectType: string,
associatedObjectId: number,
associatedObjectId: number
): RequestPromise

removeAssociation(
id: number,
objectType: string,
associatedObjectId: number,
associatedObjectId: number
): RequestPromise

properties: Properties
Expand Down
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
"main": "index.js",
"scripts": {
"build": "npm install && npm test && npm run lint",
"test": "NODE_ENV=test npm run lint && npm run mocha && npm run tsc",
"test": "cross-env NODE_ENV=test npm run lint && npm run mocha && npm run tsc",
"coverage": "nyc --reporter=lcov mocha --timeout=10000",
"lint": "npm run prettier && npm run eslint",
"tsc": "tsc",
"ts-node": "ts-node test/typescript/hubspot.ts",
"mocha": "./node_modules/mocha/bin/mocha --recursive test/ --timeout 15000",
"eslint": "./node_modules/eslint/bin/eslint.js . --fix",
"prettier": "./node_modules/prettier/bin-prettier.js --write '{lib,test}/**/*.{j,t}s'",
"watch-test": "./node_modules/mocha/bin/mocha --recursive test/ --timeout 15000 --watch"
"mocha": "mocha --recursive test/ --timeout 15000",
"eslint": "eslint . --fix",
"prettier": "prettier --write {lib,test}/**/*.{js,ts}",
"watch-test": "mocha --recursive test/ --timeout 15000 --watch"
},
"repository": {
"type": "git",
Expand All @@ -39,6 +39,7 @@
"@types/request": "^2.47.0",
"@types/request-promise": "^4.1.41",
"chai": "^4.1.2",
"cross-env": "^5.2.0",
"dotenv": "^6.2.0",
"eslint": "^5.7.0",
"eslint-config-prettier": "^3.3.0",
Expand Down
2 changes: 1 addition & 1 deletion test/contact_properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ describe('contacts.properties', function() {
.upsert(contactPropertyProperties)
.then(data => {
expect(data.description).to.eq(
contactPropertyProperties.description,
contactPropertyProperties.description
)
})
})
Expand Down
4 changes: 2 additions & 2 deletions test/contacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ const emailsFromContacts = contacts =>
contacts.flatMap(contact =>
contact['identity-profiles'].map(
profile =>
profile.identities.find(identity => identity.type === 'EMAIL').value,
),
profile.identities.find(identity => identity.type === 'EMAIL').value
)
)

describe('contacts', function() {
Expand Down
10 changes: 5 additions & 5 deletions test/lists.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('lists', function() {
before(function() {
if (process.env.NOCK_OFF) {
return createTestList(listProperties).then(
data => (listId = data.listId),
data => (listId = data.listId)
)
}
})
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('lists', function() {
before(function() {
if (process.env.NOCK_OFF) {
return createTestList(listProperties).then(
data => (listId = data.listId),
data => (listId = data.listId)
)
}
})
Expand All @@ -128,7 +128,7 @@ describe('lists', function() {
before(function() {
if (process.env.NOCK_OFF) {
return createTestList(listProperties).then(
data => (listId = data.listId),
data => (listId = data.listId)
)
}
})
Expand Down Expand Up @@ -172,7 +172,7 @@ describe('lists', function() {
before(function() {
if (process.env.NOCK_OFF) {
return createTestList(listProperties).then(
data => (listId = data.listId),
data => (listId = data.listId)
)
}
})
Expand Down Expand Up @@ -263,7 +263,7 @@ describe('lists', function() {
})
.catch(error => {
expect(error.message).to.equal(
'contactBody parameter must be provided.',
'contactBody parameter must be provided.'
)
})
})
Expand Down
6 changes: 3 additions & 3 deletions test/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('timeline', function() {
name: 'NumericProperty',
label: 'Numeric Property',
propertyType: 'Numeric',
},
}
)

describe('createEventType', () => {
Expand Down Expand Up @@ -145,7 +145,7 @@ describe('timeline', function() {
return createEventType().then(data => {
eventTypeId = data.id
return createEventTypeProperty(eventTypeId).then(
data => (eventTypePropertyId = data.id),
data => (eventTypePropertyId = data.id)
)
})
}
Expand All @@ -161,7 +161,7 @@ describe('timeline', function() {
name: 'NumericProperty',
label: 'A new label',
propertyType: 'Numeric',
},
}
)
.then(data => {
expect(data.label).to.eq('A new label')
Expand Down
Loading

0 comments on commit bcc85f5

Please sign in to comment.