To support function calls through POST API body - node.js

{
"expression":"uniqueCount('apple','grape',pickRandom('Harsha', 'Deva'))"
}
I am trying to parse this expression through a REST API function.
const functions = {
//returns the uniquecount of any element
uniqueCount: (...args) => {
return new Set(args).size;
},
ksmallest: (k, ...args) => {
//returns the kth smallest lexicographic order
console.log(k);
return [parseInt(k) - args.sort()];
},
pickRandom: (...args) => {
//picks any random element from the array
return args[Math.floor(Math.random() * args.length)];
},
};
but I am getting this error when I am testing it on ThunderClient/Postman:
{
"error": "Invalid string length"
}
While only one function works but when we call one function inside another function's parameter, it gives that error.
Expected result:
uniqueCount('apple', 'grape', pickRandom('Harsha', 'Deva'))
value of the expression is 3your text

Related

Node Express, function with parameters inside res.send

Im trying to return a value depending a parameter received. But im getting:
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received type function ([Function])
app.get('/api/:producto', (req, res) => {
const strProd = req.params.producto;
res.send( (strProd) => {
if (strProd==1) {
return "1"
} else {
return "2"
}
})
})
Thanks in advance!
As the error message says. The arguement of res.send function must be a string, buffer, array, etc. You're passing a function into the send function.
So simply put the if checks first and then give the appropriate response.
app.get('/api/:producto', (req, res) => {
const strProd = req.params.producto;
if (strProd === "1") {
return res.send("1")
} else {
return res.send("2")
}
})

node using await in for loop which calls an async function

I'm having a little trouble getting back a result from an async function I am calling in a for loop, I should be getting back a string but it is returning a promise instead
I am following this syntax but I haven't been able to get it to work properly and I'm hoping for some insight into why this fails https://eslint.org/docs/rules/no-await-in-loop
here's the function I am trying to work with, in this case decodeTheObject is async and returns a promise but if I use await decodeTheObject eslint will give me an error saying I can't use await inside a for loop, unfortunately the workaround above still results in a promise being returned instead of a resolved value
async function decode (request, encodedObj) {
const decodedArr = [];
try{
for (const id of encodedObj) {
decodedArr.push({
data: decodeTheObject(request, id), // this is an async function
partial: true,
});
}
await Promise.all(decodedArr);
return decodedArr;
}catch (err) {
throwError(
req,
{
errorDetails: [
{
issue: 'INVALID_ENCODING',
description: 'Invalid encoded obj',
},
],
},
);
}
};
// ----- calling function -----
const decodedObj = await decode(request, encodedItem);
const payload = {
newprop: decodedObj
};
Promise.all() has to work directly on an array of promises. You are passing it an array of objects which won't know how to reach into the objects to get the promises so thus, it won't accomplish anything useful. There are a couple ways to approach this.
This will await each async call in sequence, get the value and push the value into the array:
async function decode (request, encodedObj) {
const decodedArr = [];
try{
for (const id of encodedObj) {
let data = await decodeTheObject(request, id);
decodedArr.push({data, partial: true});
}
return decodedArr;
} catch(e) {
...
}
}
Or, you could run them in parallel with Promise.all() like this by creating an array of promises and using Promise.all() on that array:
async function decode (request, encodedObj) {
return Promise.all(encodedObj.map(id => {
return decodeTheObject(request, id).then(data => {
return {data, partial: true};
});
})).catch(err => {
...
});
}

How to make async function return boolean value rather than a promise

I am trying to pull the boolean value of a checkbox in my popup.html file in my chrome extension. I have this:
var highlightedCheckBoxVal = $("#highlightedCheckbox").prop("checked");
function getAsync(valueToGet) {
return new Promise((resolve) => {
chrome.storage.sync.get(valueToGet, (value) => {
resolve(value);
console.log("resolved");
})
})
}
//returns object - I want it to return true or false
$(document).keyup(async function (e) {
if (e.keyCode == 120) {
getAsync("highlightedCheckBoxVal").then(val => {
console.log(val);
});
}
});
The console returns an object, and I want it to return a boolean value. I think this is because getAsync is returning a promise, but how can I make that promise a boolean value?
I have also tried logging val.valueOf().
As we can see in the documentation the callback receives an object that contains all requested keys (you can request an array of strings) so the solution is to extract the key as result[key].
function getAsync(key) {
return new Promise((resolve) => {
chrome.storage.sync.get(key, (data) => resolve(data[key]));
});
}

Axios GET is sending the same url multiple times in Promise chain

I have a Promise chain that runs like this:
// this part is not meant to be syntactically correct
axios.get(<rest_api_that_queries_a_list_of_car_models>).then(res => {
// loop thru list and call a custom module promise
for (...) {
mymodule.getSomething(args).then(res => {
axios.post(<rest_write_to_db>).then(res => {
//we're done
....
// in mymodule
function getSomething(args) {
return getAnotherThing(args).then(res => {
// do stuff
return aThing
...
function getAnotherThing(args) {
return getThatThing(args).then(res => {
// see if pagination is greater than 1 page
if (pages == 1)
return res
let promises = [res]
for (x=2;x<pages;x++) {
// change args
promises.push( getThatThing(args))
}
return Promise.all(promises)
}).then(allres => {
return allres
})
...
// this is where it's breaking. this part is syntactically accurate
function getThatThing(args) {
let params = Object.assign(BASE_PARAMS, args.params)
console.log(args.params.model) // this logs prints a different model everytime
return axios.get(URL, {
headers: {
"Accept": ACCEPT,
"Content-Type":CONTENT_TYPE,
},
params: params
}).then (response => {
console.log(response.request.path) // this path includes the last key only everytime. so if there are 10 car models, this will search for the last model 10 times.
let result = response.data
return result
}).catch(function (error) {
console.log("search error:",error);
return error.response.data.errorMessage[0].error[0].message[0]
})
}
So basically the issue is that the axios.get command in the last function is using the same get parameters even tho I'm printing different parameters right before I make the call. I don't see how that is possible.
I was able to fix the issue by changing this line
let params = Object.assign(BASE_PARAMS, args.params)
to this
let params = {...BASE_PARAMS, ...args.params}
I can't really tell you why this fixed it. I'm assuming the Object.assign set the value to params on a global level. Perhaps someone else could provide more insight.

Async Push data to Array in Node

I'm calling mongoose query inside of another mongoose query. When I push results to a array, When ever I check it at last it is empty. After seacrching a lot, Found that issue is this executes asynchronously. But can't find how to fix the issue. My code is as follows.
Bus.find().exec(function(err,buses) {
if(err)
console.log(err);
if (buses[0] != null){
const cords = [];
buses.forEach( function (bus) {
// console.log(bus);
Position.findOne({"busId": bus.busId},{}, {sort : {'time' : -1}}, function (err, position) {
cords.push(position);
console.log(cords);
// console.log(position);
});
console.log(cords);
},
function (err) {
if (err){
console.log(err,"Errrrrrrrrrrrrr");
}
});
console.log(cords);
res.json({cords: cords});
}
Well, there are a number of problems with your code, but chief among them is the fact that you cannot save or act upon values you receive inside a callback to anything outside of that callback. Your example has (rewritten for clarity):
var result = []
arry.forEach(function(opt) {
async.call(args, function(err,value) {
result.push(value)
})
})
// result is empty here!
Which cannot work as you expect because you can not know when the inner callbacks complete.
By definition, callbacks are triggered some time in the future, and since you cannot know when, you must do all computation using the result passed to a callback in the callback itself!
Doing otherwise will give you inconsistent results.
UPDATED - Re comment
(Note: hastily typed on iPad during train ride, will fix later if needed.)
The best way would be to use Promises to aggregate the results. Here's a naive example:
/*
* given a value and an optional array (accum),
* pass the value to the async func and add its result to accum
* if accum is not an array, make it one
* return accum
*/
var do_something = (value, accum) => {
// on first pass, accum will be undefined, so make it an array
accum = Array.isArray(accum) ? accum : []
return new Promise((resolve, reject) => {
async_func(value, (err, res) => {
if(err) {
reject(err)
}
accum.append(res)
resolve(accum)
})
})
}
/*
* for each member of input array, apply do_something
* then operate on accumulated result.
*/
Promise.map(input, do_something)
.then(results => {
// results will contain the accumulated results from all
// the mapped operations
})
.catch(err => {
throw err
})
UPDATED - per comment
Using callbacks only, you can achieve the same result using:
const inputs = [...] // array of inputs to pass to async function
const expected_num_of_results = inputs.length
let results = []
const onComplete = (results) => {
// do something with completed results here
console.log(`results: ${results}`);
}
const onResult = (err, res) => { // callback to async_func
if(err) {
throw new Error(`on iteration ${results.length+1}: ${err}`)
}
results.push(res) // save result to accumulator
if( results.length >= expected_num_of_results) { // are we done?
onComplete(results) // process results
}
}
// example async func - REPLACE with actual async function
const async_func = (val,cb) => {
// call callback with no error and supplied value multiplied by 2
cb(null,val*2)
}
// wrapper that takes one value
// and calls async_func with it and predefined callback
const do_async = (value) => {
async_func(value, onResult)
}
// process inputs
inputs.forEach(do_async)
So with:
const inputs = [1,2,3,4,5]
will print:
results: 2,4,6,8,10

Resources