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

Add option to ignore limit check, use headers for limit check #152

Merged
merged 7 commits into from
Feb 9, 2019
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
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