Pagination in Zapier - javascript

I am trying following code to get all records from a paginated API in Zapier.
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
var lastCursor = null;
var output = null;
const getContent = async function (cursor) {
let actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
var apiResults = await fetch(actualUrl)
.then(resp => {
return resp.json;
});
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireContentList(results.metadata.cursor));
} else {
return results;
}
};
(async() => {
const entireList = await getEntireContentList();
console.log(entireList);
output = entireList;
callback(null, entireList);
})();
I get error as
You did not define output! Try output = {id: 1, hello: await Promise.resolve("world")};
How can I fix this?

Your problem is that though you're awaiting in that function, the top-level carries on and execution ends before your code has had a chance to run.
The good news is, Zapier wraps your code in an async function already, so you can use await at the top level (per these docs).
Try this instead:
const limitPerPage = 20;
const apiUrl = "https://myurl.com/data";
let lastCursor = null;
// var output = null; // zapier does this for you already
const getContent = async function (cursor) {
const actualUrl = apiUrl + `?cursor=${cursor}&limit=${limitPerPage}`;
const rawResponse = await fetch(actualUrl)
return resp.json() // async function, you had it as a property
}
const getEntireContentList = async function (cursor) {
const results = await getContent(cursor);
console.log("Retreiving data from API for cursor : " + cursor);
if (results.metadata.cursor !== "") {
return results.concat(await getEntireUserList(results.metadata.cursor)); // should this be named getEntireContentList?
} else {
return results;
}
};
return {
results: await getEntireContentList()
}
I noticed this is a recursive approach. That's fine, but remember that you've got limited execution time. You also might hit memory limits (depending on how many objects you're returning), so keep an eye on that.

Related

Getting SyntaxError with async/await

I have the following the following code I am trying to run with node.js:
ethereum-block-by-date.js
module.exports = class {
constructor(web3) {
this.web3 = web3.constructor.name === 'Web3' ? web3 : { eth: web3 };
this.checkedBlocks = {};
this.savedBlocks = {};
this.requests = 0;
}
.
.
.
async getEvery(duration, start, end, every = 1, after = true) {
start = moment(start), end = moment(end);
let current = start, dates = [];
while (current.isSameOrBefore(end)) {
dates.push(current.format());
current.add(every, duration);
}
if (typeof this.firstBlock == 'undefined' || typeof this.latestBlock == 'undefined' || typeof this.blockTime == 'undefined') await this.getBoundaries();
return await Promise.all(dates.map((date) => this.getDate(date, after)));
}
.
.
.
And
getBlockNumber.js
const EthDater = require('ethereum-block-by-date');
const { ethers } = require('ethers');
const url = "node url";
const provider = new ethers.providers.WebSocketProvider(url);
const dater = new EthDater(
provider
);
let blocks = await dater.getEvery('hours', '2018-11-15T00:00:00Z', '2018-11-22T00:00:00Z');
console.log(blocks);
When I run node getBlockNumber.js, I get the SyntaxError: await is only valid in async function referring to the let blocks = await dater.getEvery() function call.
If getEvery() is defined as aync in ethereum-block-by-date.js, then why is it returning this SyntaxError? When I remove await from dater.getEvery() it returns a Promise object.
The issue is resolved when I put the await dater.getEvery() inside an async function and then call the function:
async function getBlocks() {
let blocks = await dater.getEvery('hours', '2018-11-15T00:00:00Z', '2018-11-22T00:00:00Z');
console.log(blocks);
}
getBlocks();

Node JS function that return https get request final edited data

Hello everybody I have a problem with the Node JS function that I want it to return https get request final edited data, I know there are a lot of solutions for this async problem but I tried them all and still can't figure out what is wrong with my code?
here is my function without any other solutions editing:
function getMovie(apiKey, gen) {
const baseUrl = "https://api.themoviedb.org/3/discover/movie?api_key=" + apiKey + "&language=en-US&include_adult=false&include_video=false&page=1&with_genres=" + gen;
https.get(baseUrl, function (responce) {
console.log(responce.statusCode);
var d = "";
responce.on("data", function (data) {
d += data;
});
responce.on("end", () => {
const finalData = [];
const moviesData = JSON.parse(d);
const result = moviesData.results;
const maxx = result.length;
const rand = Math.floor(Math.random() * maxx);
const title = result[rand].title;
const rDate = result[rand].release_date;
const overview = result[rand].overview;
const imageRoot = result[rand].poster_path;
const movieId = result[rand].id;
const movieRating = result[rand].vote_average;
// here will push those variables to finalData array
// then return it
return finalData;
});
}).on('error', (e) => {
console.error(e);
});
}
and want after this finalData returns:
const finalResult = getMovie(apiKey, genre);
it always returns undefined, How can I fix this? please anyone ca help me with this problem
thanks in advance.
I solved this problem using promises using this code:
const rp = require('request-promise');
function getMovie(url) {
// returns a promise
return rp(url).then(body => {
// make the count be the resolved value of the promise
let responseJSON = JSON.parse(body);
return responseJSON.results.count;
});
}
getMovie(someURL).then(result => {
// use the result in here
console.log(`Got result = ${result}`);
}).catch(err => {
console.log('Got error from getMovie ', err);
});

Asynchronous execution order of multiple function each one depending on the last one

I really have hard time understanding asynchronous code, and callback function.
I want to make a sequence of function that depend on the result of the last one. The first function will import data from a data base.
import value > fctOne(Value) > fctTwo(value of fctOne(Value)) > fctThree(value of fctTwo(value)) > and so on ...
App.js will need to wait for value to be imported, so fctOne can't be synchronous. But then will all my functions behind it will need to be asynchronous too ? They have to run in order.
My failing code : with error : "callBack(result) TypeError: callBack is not a function"
DB.JSON
{"val":5,"square":25,"SquareRoot":5,"dividedByHimself":1}
on app.js
const db = require('./DB.json')
const fs = require('fs')
const path = require('path')
const dbPath = path.join(__dirname,'DB.json')
let data = fs.readFileSync(dbPath)
let userDBupdate = JSON.parse(data)
///function to import data with simulation of the delay to obtain imported value//
const value = (pathDB,callBack) => {
setTimeout((err) => {
if(err){
return callBack(new Error("loading failed"))
}
const val = db[pathDB]
callBack(val)
}, 500)
}
//// square function
let square = (pathDB, callBack) => {
value(pathDB, (val) => {
let result = val * val
userDBupdate.square = result
callBack(result)
let dataMAJ = JSON.stringify(userDBupdate)
fs.writeFileSync(dbPath, dataMAJ)
})
}
square('val')
let squareRootOfSquare = (pathDB, callBack) => {
square(pathDB, (val) => {
let result = Math.sqrt(val)
userDBupdate.square = result
callBack(result)
let dataMAJ = JSON.stringify(userDBupdate)
fs.writeFileSync(dbPath, dataMAJ)
})
}
squareRootOfSquare('val')
As jfriend00 mentioned is tried to rewrite it using promise. And yes for serial calculation it's way more easier and cleaner.
const valuePromise = new Promise((resolve,reject) => {
setTimeout(()=> {
const val = db.val
resolve(val)
})
}).then(function(resultOfCall){
let resultSquare = resultOfCall * resultOfCall
userDBupdate.square = resultSquare
let dataMAJ = JSON.stringify(userDBupdate)
fs.writeFileSync(dbPath, dataMAJ)
return resultSquare
}).then(function(resultOfSquare){
let resultRoot = Math.sqrt(resultOfSquare)
userDBupdate.squareRootOfSquare = resultRoot
let dataMAJ = JSON.stringify(userDBupdate)
fs.writeFileSync(dbPath, dataMAJ)
return resultRoot
}).then(function(resultOfSquareRoot){
let resultOfDivide = resultOfSquareRoot / resultOfSquareRoot
userDBupdate.squareRoot = resultOfDivide
let dataMAJ = JSON.stringify(userDBupdate)
fs.writeFileSync(dbPath, dataMAJ)
return resultOfDivide
})

using promises and async for protobufjs loadcall

I am trying to figure out the best way to re-write the following code:
var api = function(id, contract) {
var callback = function (error, root) {
if (error)
throw error;
var by = Buffer.from(contract,'base64')
var es = root.lookupType("Contract")
var esMsg = es.decode(by)
var esBytes = es.encode(esMsg).finish()
signature = id.sign(esBytes).toString('base64')
}
return new Promise((resolve, reject) => {
protobuf.load("contract.proto", callback)
})
}
var signContract = async(privateKey, contract) => {
let signature
var id = await crypto.keys.unmarshalPrivateKey(Buffer.from(privateKey, 'base64'))
result = await api(id,contract,signature)
}
function getSessionSignature (hash, time) {
return config.id + ":" + hash + ":" + time
}
module.exports = configure(({ ky }) => {
return async function * signbatch (input, options) {
var contracts = input.Contracts
for (var i = 0 ; i < contracts.length ; i++) {
contracts[i].contract = await signContract(config.PrivKey, contracts[i].contract)
}
//add signed contracts to the searchParams
searchParams.append("arg", JSON.stringify(contracts))
let res
res = await ky.post('storage/upload/signbatch', {
searchParams
}).json()
yield JSON.stringify({})
} else {
yield JSON.stringify({error:"Private key not found"})
}
}
})
My issue is how do I write the sign async code to pass in privateKey and contract variables to api var function and return the signature back to the result variable to be assigned to contracts[i].contract ? Please note that the id.sign(..) function is Promise inside the callback function.
You need to resolve the promise in the api function, the docs suggest you could use the single argument variant here, e.g.
var root = await protobuf.load("contract.proto");
... // (The code you currently by have in 'callback'
return signature;
As the generator is async, yield will emit a Promise which you can (obviously) handle with either .then or await

Firebase Cloud Function error, Function returned undefined, expected Promise or value

I have a cloud function which triggers on certain database write(onCreate), it works as expected but it also throws an error "Function returned undefined, expected Promise or value" though I am returning a promise.
Attaching the code snippet below. there are nested promises in it. is there a better way to handle nested promises, I already checked many posts for nested promises but not able to figure out a proper solution.
Thanks in Advance
exports.calculateAnswer = function(snap, context, dbPath,bucket) {
const answerKey = snap.val();
const incidentId = context.params.incidentId;
const matchId = context.params.match;
var globalIncidentPath = globalIncidentRootPath.replace('${match}', matchId);
globalIncidentPath = globalIncidentPath + incidentId + '/'
var pdPath = pdRootPath.replace('${match}', matchId);
pdPath = pdPath + incidentId
pdPath = pdPath + "/" + bucket
var incidentsPath = incidentsRootPath.replace('${match}', matchId);
var earningsNodePath = earningsNodeRootPath.replace('${match}', matchId);
let app = admin.app();
var globalData = null;
var globalData = null;
const globalPromise = app.database(dbPath).ref(globalIncidentPath).once('value').then(function(snapshot) {
globalData = snapshot.val();
console.log("globalData ",globalIncidentPath, "data ",globalData);
if(globalData) {
console.log("fetching pddata")
return app.database(dbPath).ref(pdPath).once('value')
}
else{
console.log("No global data found");
return true
}
}).then(function(pdSnashot){
const pdData = pdSnashot.val()
if(pdData) {
var promises = []
pdSnashot.forEach(function(childSnap){
console.log('key ',childSnap.key)
console.log('users count ',childSnap.numChildren())
childSnap.forEach(function(usersSnap){
const userId = usersSnap.key
const incidentProcessed = incidentsPath + userId + '/processed/' + incidentId
if (childSnap.key === answerKey) {
const earningUserIdEPath = earningsNodePath + userId
//const earningEPath = earningUserIdEPath + '/e/'
let gocashValue = globalData['v'];
const earningFetchPromise = app.database(dbPath).ref(earningUserIdEPath).once('value').then(function(snapshot1){
let snapDict = snapshot1.val();
var newGoCash = gocashValue
var newPDGoCash = gocashValue
if (snapDict){
let currentGoCash =snapDict['e'];
let currentPDCash = snapDict['pd']
if(currentGoCash) {
newGoCash = currentGoCash + gocashValue;
}
if(currentPDCash) {
newPDGoCash = currentPDCash + gocashValue;
}
}
const obj = Object()
obj["e"] = newGoCash
obj["pd"] = newPDGoCash
const earningPromise = app.database(dbPath).ref(earningUserIdEPath).update(obj)
const tempGlobal = globalData
tempGlobal["skip"] = false;
const processedPromise = app.database(dbPath).ref(incidentProcessed).set(tempGlobal)
return Promise.all([earningPromise,processedPromise])
});
promises.push(earningFetchPromise)
}
else{
const tempGlobal = globalData
tempGlobal["skip"] = true;
const processIncidentPromise = app.database(dbPath).ref(incidentProcessed).set(tempGlobal);
promises.push(processIncidentPromise)
}
})
})
return Promise.all(promises).then(value => {
console.log("Pd promises completed",value);
return true
})
}
else{
console.log("No Pd Data Found");
return true
}
})
.catch(function(error){
console.log('error in promise resolve',error)
})
console.log('global promise',globalPromise)
return Promise.all([globalPromise])
})
I would modify your code as follows. See the comments within the code.
var globalData = null;
const globalPromise = app
.database(dbPath)
.ref(globalIncidentPath)
.once('value')
.then(function(snapshot) {
globalData = snapshot.val();
console.log('globalData ', globalIncidentPath, 'data ', globalData);
if (globalData) {
console.log('fetching pddata');
return app
.database(dbPath)
.ref(pdPath)
.once('value');
} else {
console.log('No global data found');
// return true; Better to throw an error here
throw new Error('No global data found');
}
})
//The following 3 lines don't bring anything
//Moreover they are most probably the reason of your error as you don't return anything in this then()
//.then(function(pdSnashot){
// console.log("");
//})
.catch(function(error) {
console.log('error in promise resolve', error);
return true;
//Note that if you don't need the console.log you may ommit the entire catch since the platform will handle the error itself.
});
console.log('global promise', globalPromise);
//return Promise.all([globalPromise]); // There is no reason to use Promise.all() here since there is only one promise chain returned in globalPromise
return globalPromise;

Categories

Resources