Adding query param to mailchimp request with Node.js client library - node.js

I am trying to list out all my interests from the MailChimp api using the #mailchimp/mailchimp_marketing npm library, as that is what they use as examples for node.js in their docs.
Link to the npm library:
https://www.npmjs.com/package/#mailchimp/mailchimp_marketing
Link to the relevant documentation for this specific endpoint: https://mailchimp.com/developer/api/marketing/interests/list-interests-in-category/
Now, I can get my interests just fine with the example code there:
const run = async () => {
const response = await client.lists.listInterestCategoryInterests(
"list_id",
"interest_category_id"
);
console.log(response);
};
run();
The problem is, that by default the MailChimp API only returns the first 10 items in the list, and I need 15. There is an easy way to change this, of course, by adding a query param count=15. However, I can't find any way to pass on a query param with the listInterestCategoryInterests method as provided through the official library.
!TL;DR! So my question is:
Does anybody know how to pass on query params to the mailchimp API through the official node.js npm library, or do I really have to resort to just dropping the library entirely as it does not provide this basic functionality?

You need to list params as a string in an array:
const response = await client.lists.listInterestCategoryInterests({fields:[ "list_id,interest_category_id"]}
);
NOTE: A prefix maybe required as per below:
const response = await mailchimp.reports.getAllCampaignReports({fields:["reports.campaign_title,reports.clicks"]})
Result:
[0] {
[0] reports: [
[0] { campaign_title: 'COACT EMAIL CAMPAIGN', clicks: [Object] },
[0] { campaign_title: '', clicks: [Object] }
[0] ]
[0] }

const response = await mailchimp.lists.getListMembersInfo(listId,
{
count: 1000
});

For everyone coming here hoping to learn how to pass QUERY params into mailchimp marketing library methods:
The query parameters are taken from opts object - the object properties have to be camelCase.
In terms of which parameter for the method the opts object is - it depends on the method and you might need to check the method's source code, but probably second or third parameter.
As for the question for the concrete method, this should be the solution:
await client.lists.listInterestCategoryInterests(
"list_id",
"interest_category_id",
{ count: 15 }
);

Related

Hubspot pagination using after in nodejs

i am building hubspot api, i having trouble paginating the contacts records.
i am using #hubspot/api-client - npm for integration with hubspot and this is the docs for that https://github.com/HubSpot/hubspot-api-nodejs
hubspotClient.crm.contacts.basicApi
.getPage(limit, after, properties, propertiesWithHistory, associations, archived)
.then((results) => {
console.log(results)
})
.catch((err) => {
console.error(err)
})
in this code there is after argument, we can provide contacts id in it, and it will provide the records including and after that particular id.
How do i use this for pagination. or there is any other way.
Take a look at API Endpoints documentation for GET /crm/v3/objects/contacts and the data you receive. The getPage method returns the following data:
{
"results": [
{
// contact detail here
}
],
"paging": {
"next": {
"after": "NTI1Cg%3D%3D",
"link": "?after=NTI1Cg%3D%3D"
}
}
}
The pagination information is available in paging.next.after (if there is a consecutive page). So you can do something like this to iterate through each page:
async function doSomethingWithEachPage() {
let after = undefined;
const limit = 10;
const properties = undefined;
const propertiesWithHistory = undefined;
const associations = undefined;
const archived = false;
do {
const response = await hubspotClient.crm.contacts.basicApi.getPage(
limit,
after,
properties,
propertiesWithHistory,
associations,
archived
);
// do something with results
console.log(response.results); // contacts list
// pick after from response and store it outside of current scope
after = response.paging?.next?.after;
} while (after);
}
I rewrote the sample code to use async/await so it better works with do...while loop and omitted error handling.
If you are dealing with reasonable small amount of data and have enough of memory, you can also skip the pagination and use the getAll method to load all the data. (In fact, this method does internally a loop similar to the one above.)

Implementation of a global search for chats in telegram tdlib

I'm trying to replicate the global chat search as in telegram.
I'm using getChats method for searching, but the problem is that the method only returns a list of ids.
In addition to the id, I would also like to get the name and avatar of the chat.
Therefore, I have to go through the chatids in the forEach and for each id call the getChat method that returns the data I need. This, in turn, causes severe problems with the query execution time. (14 seconds). In a telegram, the search takes ~2 seconds. I don’t know how they did it, I re-read all the documentation and did not find a method that would allow me to pass the name of the chat and get, in addition to identifiers, also a title and an image. Has anyone already encountered a similar problem?
import BaseAction from "./BaseAction";
import airgram from "../airgram/airgram";
import { ChatsUnion, ChatUnion } from 'airgram';
class SearchChatsAction implements BaseAction
{
async run(name: string): Promise<any>
{
const output = await airgram.api.searchPublicChats({
query: name
});
const promises: Array<any> = [];
const result: Array<any> = [];
for (const chatId of (output.response as ChatsUnion).chatIds)
{
promises.push(
airgram.api.getChat({
chatId: chatId
}).then(output => {
result.push({
id: (output.response as ChatUnion).id,
title: (output.response as ChatUnion).title
});
})
);
}
await Promise.all(promises);
return result;
}
}
export default SearchChatsAction;
I think the issue you're facing is because of API. You should try using different API. If you check these two documentations:
searchPublicChat
searchPublicChats
The API you're using returns just chatIds but searchPublicChat will contain all the information of searched chat.

Google cloud tasks NodeJS api: Get queue stats?

I want to obtain the stats field for a queue in google cloud tasks using the nodejs client library #google-cloud/tasks. The stats field only exists in the v2beta3 version, however to get it we need to pass a query params readMask=*, but I don't know how to pass it using the client lib.
I tried using the otherArgs params, but its not working.
const tasks = require('#google-cloud/tasks');
const client = new tasks.v2beta3.GoogleCloudTasks()
// Get queue containing stats
const queue = await client.getQueue({name: '..'}, {otherArgs: {readMask: '*'}})
The readMask specifies which paths of the response object to fetch. The response will include all possible paths with placeholders like null, UNSPECIFIED, etc. and then contain the actual values you want.
const request = {
...
readMask: { paths: ['name', 'stats', 'state', ...] }
};
getQueue
const { v2beta3 } = require('#google-cloud/tasks');
const tasksClient = new v2beta3.CloudTasksClient();
async function main() {
const request = {
name: 'projects/PROJECT/locations/LOCATION/queues/QUEUE',
readMask: { paths: ['name', 'stats'] }
};
const [response] = await tasksClient.getQueue(request);
console.log(response);
}
main();
/*
{
name: 'projects/PROJECT/locations/LOCATION/queues/QUEUE',
...
stats: {
tasksCount: '113',
oldestEstimatedArrivalTime: null,
executedLastMinuteCount: '0',
concurrentDispatchesCount: '0',
effectiveExecutionRate: 500
}
}
*/
listQueues
const { v2beta3 } = require('#google-cloud/tasks');
const tasksClient = new v2beta3.CloudTasksClient();
async function main() {
const request = {
parent: 'projects/PROJECT/locations/LOCATION',
readMask: { paths: ['name', 'stats'] }
};
const [response] = await tasksClient.listQueues(request);
console.log(response);
}
main();
/*
[
{
name: 'projects/PROJECT/locations/LOCATION/queues/QUEUE',
...
stats: {
tasksCount: '1771',
oldestEstimatedArrivalTime: [Object],
executedLastMinuteCount: '0',
concurrentDispatchesCount: '0',
effectiveExecutionRate: 500
}
},
...
]
*/
By taking a look at the source code for the client library I see no reference for the readMask parameter as specified on the v2beta3 version of the REST API projects.locations.queues.get method.
The relevant method on the NodeJS client library getQueue() expects a type of request IGetQueueRequest that doesn't have the readMask parameter and is only expecting the name property.
Nonetheless this implementation might change in the future to include a relevant method to get the stats.
Regarding the REST API itself, there is an error on the public docs on the readMask section as * is not a valid character. If you want to get the Queue.stats field you should simply enter stats on the readMask parameter. If you want to get all the relevant fields you should enter all of them (e.g. name,rateLimits,retryConfig,state,taskTtl,tombstoneTtl,type,stats should get all the relevant fields you get from calling the method + the Queue.stats field).
The following picture should help you.
As a workaround if you click on the expand symbol on the Try this API section of the docs for the relevant method you could click on the JAVASCRIPT section and get the relevant code as how to build the request as shown on the following picture.
EDIT JANUARY 23rd 2020
The documentation was corrected to inform that in order to express that:
[Queue.stats] will be returned only if it was explicitly specified in the mask.
Which translates that simply writing stats under the readMask field will return the stats.

Mongoose/NodeJS - Sort button in .EJS template

In my Mongoose controller I am sorting according to creation date of the product:
let products = await Product.find().sort({ 'createdAt': -1 });
I want to create a button in EJS template which allows the user to select different criteria to sort by (e.g. price). Creating the button itself is no problem, but I don't know how to access the sort function in the controller when an option is selected (e.g. if price selected, sort by price), and where I should be putting the code, in the controller or in the EJS template?
I assume I should be using req.query, but I don't know how. Thanks.
Part One - Abstraction Mongoose API to JS
Mongoose allows you to build your query in sections. Let say you have a function the query Product with additional options object.
findOptions - contains the filter options (the where part of the query)
pagingOptions - contains sorting+ordering,, page and pageSize.
This is all the context you need to build a query.
async function getProducts(findOptions, pagingOptions) {
const query = Product.find(findOptions);
if(pagingOptions.sort) {
// Note: This example assumes that paging.sort has the same structure as Monguse sort object.
query.sort(paging.sort);
}
let products = await query.exec();
...
return products;
}
Usage:
let products = await getProducts({}, { 'createdAt': -1 });
let products = await getProducts({ 'createdAt': { $gt: Date.now() }}, { '_id': 1 });
You can add or restrict many many things using the options object to manage the query context
See: mongoose query doc
Part Two - Exposing an API
Now that we have a method at the server-side that can query the Products using only JS object (JSON) you will need to expose an HTTP API so a client will be able to call the server with his query criteria.
Let defined this is the HTTP API that we will send to the client to integrate with:
POST /products
// request body
{
sort: { FIELD_NAME: ASC|DESC }, // ASC=1, DESC=-1
}
Usage:
curl -X POST -H "Content-Type: application/json" --data '{ sort: { "createdAt": "1" } }' http:localhost:3000
Note: you can extend both the HTTP API and the Backend method options to extend the functionality further.
See the following to check how to implement HTTP endpoint via express
https://expressjs.com/en/guide/routing.html
http://expressjs.com/en/resources/middleware/body-parser.html#bodyparserjsonoptions
Part Three - FrontEnd Integration
Now all is left is to implement an HTTP client and expose the HTTP API so the rest of the FrontEnd modules will be able to call the backend.
The following is a simple fetch example but you can use any HTTP client lib that you like.
const productsEndpoint = baseUrl + '/products';
async function getProducts(options) {
const response = await fetch(productsEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(options)
});
return response.json();
}
These three steps will you to have a well-defined API across components and the layers within them.

Getting coordinates from Yandex Map API Geocoder via multi-geocoder in NodeJs

I need to get coordidinates of set of addresses to display them on Yandex Map widget. There a lot of addresses, so I am going to get coordinates on the nodejs serverside. I have found package multi-geocoder, that looks exactly the solution for me. So I've written the example:
import MultiGeocoder from "multi-geocoder"
const geocoder = new MultiGeocoder({
provider: 'yandex',
coordorder: 'latlong',
lang: 'ru-RU',
apikey: 'My API key from https://developer.tech.yandex.ru/'
});
geocoder.geocode(['Москва'], {
apikey: 'My API key from https://developer.tech.yandex.ru/'
})
.then(function (res) {
console.log(res);
});
I got the response:
{
result: { type: 'FeatureCollection', features: [] },
errors: [ { request: 'Москва', index: 0, reason: 'Forbidden' } ]
}
I assume that something went wrong with apiKey, but cant figure out what exactly. How to get coordinates properly from nodejs script? Is it possible\legal at all?
Thank you.
If you have any problems with the API key, you should contact Yandex. Maps support. The problem may be with the key itself, or with your IP/domain. Only Yandex can determine the exact cause.
If you need to add points from the geocoder to the map, then it is easier to use geocoding in the JS API. It is enough to simply sequentially process the elements of the address array:
var searchArr = ['Москва, Фадеева, 5','Москва, Трубная, 31','Москва, Маросейка, 11'];
searchArr.forEach(function(item) {
ymaps.geocode(item, {
results: 1
}).then(function (res) {
var firstGeoObject = res.geoObjects.get(0),
coords = firstGeoObject.geometry.getCoordinates();
myMap.geoObjects.add(firstGeoObject);
});
});
If you display the data received from the data on a Yandex map and follow the other terms of use, the Yandex.Map API is available for free.
If at least one of the conditions must be violated, you should switch to a commercial license. Check out the fees here: https://tech.yandex.com/maps/tariffs/doc/jsapi/prices/index-docpage/

Resources