madkudu / node-hubspot Goto Github PK
View Code? Open in Web Editor NEWNode wrapper for the HubSpot API
License: MIT License
Node wrapper for the HubSpot API
License: MIT License
Would like to be able to override the Bottleneck limiter options (or at least fix the default options) to allow for requests to be processed concurrently.
In the current version the Bottleneck limiter has minTime
set to 1000, delaying each request by 1s. I think it was intended to allow for 9 concurrent requests with maxConcurrent
set to 9, but it will almost always only run one at a time since requests should resolve before the 1s delay.
Lines 20 to 24 in 169e0f5
Changing minTime
to something like 1000 / 9 will keep it under the 10 requests per second limit.
const Bottleneck = require('bottleneck')
const limiter = new Bottleneck({
maxConcurrent: 9,
minTime: 1000 / 9,
})
Might need some tweaking to account for errors. In one application where I tested it, some of the emails being uploaded would bounce back errors and cause some of the following requests to hit the limit.
I'd be happy to work on a PR for this, but I wanted to make sure there weren't any other gotchas that I needed to watch out for.
I dont think you want to throw in your promise https://github.com/brainflake/node-hubspot/blob/master/lib/client.js#L110 since it will cause the catch below to call the callback with the error twice.
Build is currently failing because some tests (workflows for example) rely on objects that are not guaranteed to exist in the sandbox.
Rest API supports passing multiple properties to query params, this is extra helpful when you want to see which pipeline and stage a deal belongs to. Otherwise you will need to send more API requests in order to get those properties.
When i use this method i got an error: "UserId not provided in request". I can see that some other methods use it, but not this one.
@brainflake What endpoints are missing from the library? Can we create a list of them and add so we could start to work on adding it and creating test so maybe next major release has all endpoints?
Also they just release the new timeline and webhooks api's maybe it will be good to go ahead and start to think how to include there.
This function is missing from README:
client.contacts.createOrUpdate(email, data, cb)
See line 89 of index.js for definition.
I can confirm this function works, as I have used it in my own code.
I tried to make fork and PR, but hit some SSH issues that I didn't have time to fix.
I'm trying to decode error object message
async createContact(data) {
try {
let contact = await this.hubspot.contacts.create(data)
return contact;
}catch(e){
debug('error object',e)
throw new Error(e)
}
}
I get this print in terminal
Error: StatusCodeError: 409 - {"status":"error","message":"Contact already exists","correlationId":"3c5db087-36d0-415c-94ef-039de03b848a","identityProfile":{"vid":2751,"identity":[{"value":"[email protected]","type":"EMAIL","timestamp":1545572760708,"isPrimary":true},{"value":"a389c82e-60b3-4ef0-9c7c-4f19e432c0d3","type":"LEAD_GUID","timestamp":1545572760719}],"linkedVid":[],"isContact":true,"savedAtTimestamp":1545572760723},"error":"CONTACT_EXISTS","requestId":"71e6085bfec2c5d13046f6b344beed0e"}
but when I can't print the error message, it's not object.
After the Oauth flow the hubspot object does not contain the accessToken "expires_in" data.
Such data is useful for setting the local cache lifetime properly
when doing a query against the contacts api or any other api that can returned paged results, is there a built in method to get all the results? Or do we need to create our own iterator to do it? A quick example in the README.md would be awesome!
When using Bottleneck in clustering mode, it is strongly recommended to set expiration
on every job.
See https://github.com/SGrondin/bottleneck#important-considerations-when-clustering
It would be great if hubspot would pass an expiration
to calls to this.limiter.schedule
, e.g.
return this.checkApiLimit(params).then(() => {
this.emit('apiCall', params)
return this.limiter.schedule({ expiration: this.apiTimeout }, () =>
request(params)
.then(res => {
this.updateApiLimit(res)
return res
})
.then(res => res.body)
) // limit the number of concurrent requests
})
then if I setup clustering mode for hubspot's bottleneck instance, it will apply this recommendation.
i'm working on a project that may need this, is there anyone working on implementing these features?
Pretty pleaseeee??
Hello,
I was wondering if there are any plans to implement the new CRM APIs in the future?
The old API used to go from a company to associated deals is being deprecated and replaced by a more generic association API described here https://developers.hubspot.com/docs/methods/crm-associations/get-associations
Thank you.
Given the following code
'use strict';
const Hubspot = require('hubspot');
const hubspot = new Hubspot({ apiKey: 'demo' });
const opts = {};
return hubspot.owners.get(opts)
.then(results => {
console.log("Successful get request of owners")
console.log(results);
return results;
}).catch(err => {
console.log("Failed get request of owners")
console.log(err);
});
I get the following error message:
Failed get request of owners
TypeError: cb is not a function
at limiter.schedule.then.catch.err ((path omitted)/node_modules/hubspot/lib/client.js:120:13)
at <anonymous>
This is because Owner.get currently only takes an argument of cb
, rather than opts, cb
as stated in the documentation, where it said hubspot.owners.get(opts, cb)
I haven't looked into whether the documentation should be changed to get rid of opts
, or whether the implementation should be changed to utilize supplied options.
contacts.getById
only takes id
, but per Hub Spot spec there are more options that can go into the URL query string (as it is a GET)
https://developers.hubspot.com/docs/methods/contacts/get_contact
string[]? property
string? propertyMode // "value_only", "value_and_history"
string? formSubmissionMode // "all", "none", "newest", "oldest"
boolean? showListMemberships
Solution:
Add an options
param which accepts these values and adds them to qs
The signature is slightly different to the equivalent company/deal versions documented
includePropertyVersions
paramSome of the HubSpot API Calls don't return any messages (like the update call - https://developers.hubspot.com/docs/methods/contacts/update_contact), and the status code needs to be validated to determine the success of the calls. Currently, the tests for node-hubspot wrapper validates the test as a success if the message returned is undefined, but that is not necessarily true. As per the HubSpot API documentation, all of the following cases will return an undefined message
Hey guys, any chance of a bump on the version number of request (>=v2.74.0)? Current one you are using is insecure:
https://nodesecurity.io/check/hubspot
Great tool by the way!
https://github.com/brainflake/node-hubspot/blob/d99b4c0f6871c7f484ef7ae8bfa2d9cc6dbc9b4a/lib/client.js#L24 cb is not defined here
Running a method without setting a key first will result in the following error
.../node_modules/hubspot/lib/client.js:24
return cb(new Error("You must provide a key."));
^
ReferenceError: cb is not defined
at Object.useKey (.../node_modules/hubspot/lib/client.js:24:14)
@AustinLeeGordon looks like we were able to move past the prettier issue but now it is telling me there is another error...which i believe is another prettier issue
Detailed stack trace: /user_code/node_modules/hubspot/lib/oauth.js:12
...data,
^^^
SyntaxError: Unexpected token ...
at createScript (vm.js:56:10)
Originally posted by @PrimalIan in #154 (comment)
This may be a typscript specific issue. When i try to use the contacts.createOrUpdate method i get an error. It requires two inputs into it. a string which would be the email and a data object. All the other methods like create require a JSON object but when i try to use it like this:
const contact_data = { 'properties': [ { "property": "email", "value": postData.email }, { "property": "firstname", "value": postData.f_name }, { "property": "lastname", "value": postData.l_name }, { "property": "company", "value": postData.company }, { "property": "phone", "value": postData.phone }, { "property": "state", "value": postData.state } ] };
it gives me this error:
[ts] Argument of type '{ 'properties': { "property": string; "value": any; }[]; }' is not assignable to parameter of type '{}[]'. Property 'length' is missing in type '{ 'properties': { "property": string; "value": any; }[]; }'.
i make the call like this:
return hubspot.contacts.createOrUpdate(postData.email, contact_data)
The useKey function requires a callback function for errors, but doesn't call it on success, which means that it can't be used properly.
function useKey (key, cb) {
if (!key || typeof key !== 'string') {
return cb(new Error("You must provide a key."));
}
self.key = key;
}
It should probably be:
function useKey (key, cb) {
if (!key || typeof key !== 'string') {
return cb(new Error("You must provide a key."));
}
else {
self.key = key;
return cb(null);
}
}
Hi guys
Thanks for what is available so far.
I was wondering wether you had in mind to support the Forms?
Cheers
Sam
Instead of maintaining definitions separately (always flaky)
Added a support for checking API limits:
But couple issues:
Will try to do a cleaner implementation soon.
This bug is about the new Hubspot
constructor's signature being incorrect according to the TypeScript engine when taking an example from the documentation.
The steps to reproduce the bug are:
node-hubspot-issue
typescript
& ts-node
packages.$ yarn add --dev typescript ts-node
node-hubspot
package as well.$ yarn add --dev node-hubspot
index.ts
at the root of the node-hubspot-issue
folder.import Hubspot from 'hubspot';
const hubspot = new Hubspot({
clientId: '...',
clientSecret: '...',
redirectUri: '...',
refreshToken: '...'
});
$ yarn ts-node index.ts
The expected behavior was to not have any errors thrown when using the constructor's signature from the documentation.
Environment:
options.maxUsePercent || MAX_USE_PERCENT_DEFAULT
will default to MAX_USE_PERCENT_DEFAULT
if maxUsePercent = 0
AS title suggests, if you're running a bunch of API calls, they'll start failing and you'll get the following error:
{“status”:“error”,“message”:“You have reached your secondly limit.”,“errorType”:“RATE_LIMIT”,“correlationId”:“6828d000-3d2f-4701-8d90-b21e53b0d005”,“policyName”:“SECONDLY”,“requestId”:“ce6a6a91-ac17-492f-bbdb-7d72477c319c”}
The API checker currently hits the APILimit end point, but that endpoint only handles the daily limit.
Not sure the best way to handle it, but a quick fix might be to use the .delay chain function on the request-promise object
There are some functions that take a callback as the second argument but we have code allowing one to pass it as the first. This seems to happen inconsistently and not be documented anywhere.
I think it's worth removing callbacks as the first argument. It may also be an option to remove callbacks entirely and document how to use promises and then
to achieve the same functionality.
Would be great to have at least some unit tests.
Specifically companies.getById
Hi,
I'm working on a project require the workflows feature. Any chance that supports this feature in the future?
Thanks.
Luke
Hey, could be handy to let the users associate/removeAssociation of many contacts or companies at once, the hubspot API supports it and it could save some requests, maybe create a new function like associateMany
or tweak a little the current one without breaking the current behavior, I could open a PR for that. WDYT?
const Hubspot = require('hubspot');
const hubspot = new Hubspot({
clientId: process.env.HUBSPOT_CLIENT_ID,
clientSecret: process.env.HUBSPOT_CLIENT_SECRET,
redirectUri: `http://localhost:${PORT}`,
refreshToken: "someStringHere"
})
return hubspot.refreshAccessToken()
.then(results => {
console.log(results.access_token)
console.log(hubspot.accessToken) // this assigns the new accessToken to the client, so your client is ready to use
return hubspot.contacts.get()
})
.catch((err)=> console.log(err))
This method does not work. I'm getting a 400 BAD_REFRESH_TOKEN
error message.
I've diagnosed the problem as a poor refreshToken when instantiating the client which throws an error before I can get to the refreshToken() method.. I searched the website and forums for what should be in the refresh token property... can't find anything.
Anyone know where I can find what should go here?
Hey,
The request used to search companies by domain does not work anymore, the method and uri have changed.
Source : https://developers.hubspot.com/docs/methods/companies/search_companies_by_domain
not sure it is appropriate to ask a question here, but I have been struggling with initiating oAUTH with this Library. When I get authenticated I plan on adding timeline create functionality. I just have no idea what I am doing wrong. I used a sample app so I know I am on the right track with my variables. Here is my code, I desperately need a bump in the right direction. Maybe we could do a screen share and willing to pay as I have been battling this for 2 days. Guessing it is something simple I am missing.
I keep getting BAD_AUTH_CODE, "missing or unknown auth code". I could get data via APIkey but the timeline calls require oAUTH. My email is [email protected]
const chai = require('chai')
const expect = chai.expect
const Hubspot = require('hubspot')
class hubspotapi {
authorize(params) {
return new Promise((resolve, reject) => {
let body = '';
if(params.client_id) {
const pams = {
code: 'codecodecode',
clientId: 'xxxxx',
clientSecret: 'yyyyyyy',
redirectUri: 'https://plainsmobile.com'
//
}
const hubspot = new Hubspot(pams)
return hubspot.oauth.getAccessToken({
pams // the code you received from the oauth flow
}).then(data => {
expect(res).to.have.a.property('access_token')
})
return hubspot.contacts.get().then(data => {
expect(data).to.be.a('object')
expect(data.contacts).to.be.a('array')
expect(data.contacts[0]).to.be.an('object')
})
//return hubspot.refreshAccessToken()
// .then(results => {
// console.log(results.access_token)
// console.log(hubspot.accessToken) // this assigns the new accessToken to the client, so your client is ready to use
// return hubspot.contacts.get()
// })
resolve(response);
} else {
resolve();
}
});
}
}
module.exports=hubspotapi;
hubspotapi.txt
Hi there,
Was wondering if you had plans to add workflows to the lib.
I am trying to deploy a project to cloud functions. i switched from TS to JS to try to get better usability with this and other packages. But every time I add const Hubspot = require('hubspot');
I get an error on deployment that halts everything.
Is there a syntax error in your code?
Detailed stack trace: /user_code/node_modules/hubspot/lib/company.js:89
)
^
SyntaxError: Unexpected token )
at createScript (vm.js:56:10)
at Object.runInThisContext (vm.js:97:10)
at Module._compile (module.js:549:28)
at Object.Module._extensions..js (module.js:586:10)
at Module.load (module.js:494:32)
at tryModuleLoad (module.js:453:12)
at Function.Module._load (module.js:445:3)
at Module.require (module.js:504:17)
at require (internal/module.js:20:19)
at Object. (/user_code/node_modules/hubspot/lib/client.js:3:17)
at Module._compile (module.js:577:32)
at Object.Module._extensions..js (module.js:586:10)
at Module.load (module.js:494:32)
at tryModuleLoad (module.js:453:12)
at Function.Module._load (module.js:445:3)
at Module.require (module.js:504:17)
It would be nice to automatically retry if we get error 429 back from the server, indicating we have sent too many requests.
This is relatively easy to implement using bottleneck, see https://github.com/SGrondin/bottleneck#retries
If retries are not wanted as a default, perhaps the hubspot client object could pass-through the relevant events from bottleneck so the user of hubspot can listen to them, and provide an example in the docs how to add appropriate error handlers to retry.
To workaround the issue, we can add our own event handler on the limiter, but it requires accessing the undocumented internals of the hubspot client:
const hubspotClient = new Hubspot({
apiKey,
limiter: {
id: 'hubspot',
maxConcurrent: 2,
minTime: 150,
// Clustering options
datastore: 'ioredis',
clearDatastore: false,
clientOptions: redisClientOptions,
timeout: 60000,
},
});
const errorMaxRetries = (error: any) => {
switch (error.statusCode) {
case 502:
case 503:
case 427: {
return 10;
}
case 500: {
return 1;
}
}
switch (error.code) {
case 'ECONNRESET':
case 'ESOCKETTIMEDOUT':
case 'ETIMEDOUT':
return 10;
}
return 0;
};
((hubspotClient as any).limiter as Bottleneck).on(
'failed',
async (error: any, jobInfo: any) => {
if (jobInfo.retryCount < errorMaxRetries(error)) {
log.warn(error, 'Retrying HubSpot request.');
return 500;
}
},
);
Hi team
Just a minor suggestion - v1.3.4 updated automatically for us from NPM, and then we got a series of errors (copy below). I think it's the trailing comma @ https://github.com/MadKudu/node-hubspot/blob/1.3.4/lib/broadcast.js#L18
Suggest maybe unpublishing v1.3.4 rather than keep it live? Just to avoid others having same problem.
/var/app/current/node_modules/hubspot/lib/broadcast.js:19
)
^
SyntaxError: Unexpected token )
at Object.exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:543:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at Module.require (/var/app/current/node_modules/require-in-the-middle/index.js:43:24)
at require (internal/module.js:20:19)
at Object. (/var/app/current/node_modules/hubspot/lib/client.js:1:81)
I wanted to migrate to this node module from https://github.com/Datahero/node-hubspot
In the other module I am able to do something like:
api.get_pages({is_draft: false}.. )
Is there an equivalent method in this module?
https://github.com/MadKudu/node-hubspot/blob/master/lib/oauth.js line 12
I seemed to have "Fixed" the error by deleting all the ...data spread from this page.
Can someone provide input on what this will do?
Thanks!
Would be willing to help develop this if I could get some guidelines.
Im getting the error: "Cannot use 'new' with an expression whose type lacks a call or construct signature." when i try to use the code const hubspot = new Hubspot({apikey: <apiKey>})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.