Node.js pomise async method return undefined - node.js

I have created a node.js application using promise. I have following code
async clientCall() {
const baseUrl = 'https://localhost:44300/test';
const queryString = '';
var options = {
uri: baseUrl + queryString,
};
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
var result = await request.get(options, function (err: any, res: any, body: any) {
console.log("Result: ", body)
return body;
})
console.log("response:",result);
// return result;
}
await ClientRepository.clientCall().then(data => {
console.log("inside data: ",data)
return data;
})
But i got output like this
response:
Result: My response
inside data: undefined
inside data: My response
I need to return response only after await request is completed.

I think the following is your solution. If a Promise is passed to an await expression, it waits for the Promise to be fulfilled and returns the fulfilled value.
async function clientCall() {
return new Promisse((resolve, reject) => {
const baseUrl = 'https://localhost:44300/test';
const queryString = '';
var options = {
uri: baseUrl + queryString,
};
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
request.get(options, function (err: any, res: any, body: any) {
resolve(body);
})
});
}
async function callClientCall(){
let clientCallResult = await ClientRepository.clientCall();
}
Simple example:
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();

Related

how to wrap axios function and let parent to wait?

here's I've my axios function wrapped within a custom function:
async function getOrder(orderId) {
// ...
await axios({
method: 'post',
url: endpoint + "/mymethod",
data: request
}).then(function (response) {
var data = response.data.result;
return data;
}).catch(function (error) {
return { "error": error };
});
}
but if than i call that function:
router.get('/getOrder/:id', (req, res) => {
let result = getOrder(req.params.id);
res.json(result);
})
it returns nothing (since its async and don't wait the .then()).
what's the best way to wrap axios/async function and call from outside?
I think you're missing await in your codes:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
====================
[New Update]
for me in API function:
async getOrder(orderId) {
try {
const response = await axios.post(endpoint + "/mymethod")
return response.data
} catch (error) {
return { "error": error }
}
}
and get the result:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
===========
[New Update2] here is my sample async/await function with axios
const axios = require("axios")
async function getOrder(orderId) {
try {
const response = await axios.get("http://google.com")
return response.data
} catch (error) {
return { "error": error }
}
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
====================
[New Update3] new Promise with axios:
const axios = require("axios")
async function getOrder(orderId) {
// try {
// const response = await axios.get("http://google.com")
// return response.data
// } catch (error) {
// return { "error": error }
// }
return await new Promise((resolve, reject) => {
axios({
method: 'get',
url: "http://google.com"
}).then(function (response) {
var data = response.data
resolve(data)
}).catch(function (error) {
reject({ "error": error })
});
})
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
I think you are missing an await so you do not return a promise but wait for the result of getOrder to be passed in res.json :
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})

Response doesn't wait for async function

I found the aproach how to put the async function into a router endpoint and tried to implement it but not suceed. E.g. this link zellwk.com
The server sends only empty string instead of a huge string that is on snippet.host.
async function downloadData(url) {
const options = {
'method': 'GET', 'url': url, 'headers': {}, formData: {}
};
let result = '';
await request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body)
result = response.body
});
return {error: 0, text: result}
}
app.get('/token/:token', jsonParser, async function (req, res) {
console.log(req.params.token) //Don't mind this token
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
How to make it wait for the download?
EDIT
I implemented node-fetch and got this:
{"error":0,"text":{"size":0}}
What did I wrong?
async function downloadData(url) {
const result = await fetch(url)
return {error: 0, text: result}
}
app.get('/token/:token', jsonParser, async function (req, res) {
console.log(req.params.token)
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
in case of fetch call the response body need to be parsed first which you are missing.
async function downloadData(url) {
const res = await fetch(url)
if (res && res.status != 200)
throw new Error("status code other than 200 received")
let json = await res.json()
return {error: 0, text: json}
}
app.get('/token/:token', async function (req, res) {
console.log(req.params.token)
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
// let json = await message.json()
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
i tried calling the api but every time it is returning 404 . so json cant be called in that case. but if 200 is returned then you call json and return that accordingly.
You can only usefully await a promise.
request doesn't return a promise, it takes a callback function instead.
This is one of the reasons that request was deprecated two years ago.
Replace request with something which supports promises such as node-fetch, the native fetch that was added to Node.js recently, or axios.
In case you must use request (eventhough it's deprecated); or in case you find a similar situation with a old function that doesn't return a promise; you can turn your request into a function that returns a promise.
Either write your own wrapper, in the form of
function requestPromise(options) {
return new Promise(
(resolve,reject) => request(options,
(err,response) => if (err) reject(err) else resolve(response)));
}
or, given that request's callback is in the form of function(err,response), directly use util.promisify
async function xxxx(...) {
try {
...
let response = await util.promisify(request)(options);
...
}
Because request isn't actually an async function that returns a Promise, you can create your own async version of request.
function asyncRequest(options) {
return new Promise((resolve, reject) => {
request(options, (err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
})
}
Then in your project rewrite your downloadData function to be:
async function downloadData(url) {
const options = {
method: "GET",
url: url,
headers: {},
formData: {},
}
const result = await asyncRequest(options)
return { error: 0, text: result.body }
}

Await doesn't actually wait for an async function to complete

I'm starting to use Redis for caching in my NodeJS app. Unlike all the tutorials that can be found on the internet (for example this one: https://medium.com/geekculture/fasten-your-node-js-application-with-a-powerful-caching-mechanism-using-redis-fd76b8aa482f), I don't send the res just after calling the "cache" function. My "cache" function is a middleware returning a value if found.
Here is where the function is called:
const { requestLDAP } = require('../utils/ldap')
router.get('/:mode/:type/:code', async (req, res) => {
(...)
const resultLDAP = await requestLDAP(
type, params
);
console.log('---');
console.log(resultLDAP);
console.log('---');
And here is the part of the LDAP module:
async function requestLDAP(type, params) {
const key = JSON.stringify({type,params});
// checking the cache
await clientRedis.get(key, async (err, response) => {
if (response) {
console.log("[CACHE]");
return {
ok: true,
contenu: JSON.parse(response),
};
} else {
const simulated = Array.from({ length: 5 }, () => {
let r = { type: type.slice(0, -1) };
params.forEach((k) => {
r[k] = `${cle}_${Math.floor(100*Math.random(100))}`;
});
return r;
});
console.log("[API]");
await clientRedis.setex(cle, 10, JSON.stringify(simulated));
console.log('[SAVED]');
return {
ok: true,
contenu: simulated,
};
(...)
I don't write all the rest, which is basically all the actual LDAP call.
My problem is that the script doesn't seem to wait for the "await" to complete. Here is what I have in the console:
---
undefined
---
---
undefined
---
[CACHE]
[CACHE]
What am I missing here?
If I write console.log(response) I have the correct response, but once again AFTER expected.
[EDIT]
After helpful comments, here is how I wrote the function:
let finalResponse = await clientRedis.get(cle, async (err, response) => {
if (response) {
console.log("[CACHE]");
return response;
} else {
(...)
return {
ok: true,
contenu: finalResponse,
};
but finalResponse is a boolean, it doesn't return the real response.
As they said before, requestLDAP function returns nothing, not an actual Promise that you can wait for.
You need that requestLDAP returns a Promise because you are waiting for the result of clientRedis that you don't know when will you have it.
When you have it, you have to resolve or reject the Promise mentioned. A return here is not a return for requestLDAP, but for the caller of the callback.
Try packing and returning a promise like this:
async function requestLDAP(type, params) {
return new Promise( async (resolve,reject) => { // --> Promisify the asynchronous response
const key = JSON.stringify({type,params});
// checking the cache
await clientRedis.get(key, async (err, response) => {
if(err) reject('Something ugly happened here'); // --> Give a result for the promise in the future
if (response) {
console.log("[CACHE]");
resolve( { // --> Give a result for the promise in the future
ok: true,
contenu: JSON.parse(response),
} );
} else {
const simulated = Array.from({ length: 5 }, () => {
let r = { type: type.slice(0, -1) };
params.forEach((k) => {
r[k] = `${cle}_${Math.floor(100*Math.random(100))}`;
});
return r;
});
console.log("[API]");
await clientRedis.setex(cle, 10, JSON.stringify(simulated));
console.log('[SAVED]');
resolve( { // --> Give a result for the promise in the future
ok: true,
contenu: simulated,
} );
(...)
}
});
}
};

node js call a promise function inside a chain .then

Hello I am new working with asynchronous calls I hope you can help me.
I have a .then chain where I want to call in the middle of the chain a function that returns a promise but it happens to me that the chain does not wait for it to have the result of the promise function and continues without waiting
var User = require('../models/user_model');
var mapbox = require('./helper/request_api_mapbox');
findOne_mapbox: (req, res) => {
User.findById(req.params.id)
.then(user => {
...
return user.address;
})
.then(function (adress_to_mapbox)
{
// mapbox.connect_mapbox returns a promise
mapbox.connect_mapbox(adress_to_mapbox)
.then(mapbox_coordinates => {
//inside this console.log is not read it
console.log("2 then mapbox_coordinates ", mapbox_coordinates)
return Promise.resolve(body);
})
})
.then( mapbox_coordinates => {
// in this console.log mapbox_coordinates returns undefined
console.log("last promise mapbox_coordinates",
mapbox_coordinates)
// I want to return mapbox_coordinates
return res.status(200).send({
"response": "I only receive this string "
});
})
}
the promise function is:
'use strict'
const rp = require('request-promise');
const access_token_mapbox = 'bla bla bla private';
function connect_mapbox(adress_to_mapbox) {
return new Promise((resolve, reject) => {
var options = {
method: 'GET',
uri: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + adress_to_mapbox + '.json?access_token=' + access_token_mapbox,
json: true // Automatically stringifies the body to JSON
};
rp(options)
.then(body => {
if (body.hasOwnProperty('errcode') && body.errcode != 0) {
return Promise.reject(body);
}
console.log("inside connect_mapbox function on mapbox_model 2", body)
return Promise.resolve(body);
})
.catch(err => {
debug(err);
return Promise.reject(err);
})
})
}
module.exports = { connect_mapbox };
Inside the promise function I can see in my console.log that it makes the api call properly and the response body is ok.
I am starting in the programming, I solved the problem in the following way although I don't know if it is the most correct
I solved it by converting the connect_mapbox promise function to async await and the .then chain to async await like so:
'use strict'
const rp = require('request-promise');
const access_token_mapbox = 'bla bla bla private';
async function connect_mapbox(adress_to_mapbox) {
try {
var options = {
method: 'GET',
uri: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + adress_to_mapbox + '.json?access_token=' + access_token_mapbox,
json: true // Automatically stringifies the body to JSON
};
let response = await rp(options);
console.log("inside connect_mapbox function on mapbox_model", response)
if (response.hasOwnProperty('errcode') && body.errcode != 0) {
return Promise.reject(response);
}
return Promise.resolve(response);
}catch(error) {
return Promise.reject(error);
}
}
module.exports = { connect_mapbox };
And the .then chain like
var User = require('../models/user_model');
var mapbox = require('./helper/request_api_mapbox');
findOne_mapbox: (req, res) => {
User.findById(req.params.id)
.then(user => {
...
return user.address;
})
.then(async function (adress_to_mapbox)
{
console.log("adress_to_mapbox thit could be deleted", adress_to_mapbox)
let mapbox_response = await mapbox.connect_mapbox(adress_to_mapbox)
console.log("async mapbox_response", mapbox_response)
return res.status(200).send({
mapbox_response
});
})
...
}

Regressive call in promise

Is there any easy way to do recursive call using promise. Here is my sample.
function getData() {
var result=[];
var deferred = Q.defer();
(function fetchData(pageno){
var options = {
method : 'GET',
url : 'example.com/test',
qs:{
pageNo: pageno
}
}
request(options, function (error, response, body) {
if (error)throw new Error(error);
if (body.hasMorePage == true) { //checking is there next page
result.push(body)
fetchData(++body.pageno); // getting next page data
} else {
deferred.resolve(result); // promise resolve when there is no more page
}
});
})(0);
return deferred.promise;
}
getData().then(function(data){
console.log(data)
});
Let's consider API is giving more data in consecutive calls. in order to collect all the data, I need to use some parameter (EX:hasMorePage) from previous call response. I need to go regressive call only for obtaining this scenario, but I would like to know a better(Promise) way.
Most welcome.
async function request(options, callback) {
// simulate server response of example.com/test with 1 second delay
const totalNumberOfPages = 3;
const pageNo = options.qs.pageNo;
await new Promise(resolve => setTimeout(resolve, 1000));
const hasMorePages = pageNo < totalNumberOfPages;
const body = { hasMorePages };
callback(void 0, { body }, body);
}
function getPage(pageNo) {
const options = {
method: 'GET',
url: 'example.com/test',
qs: { pageNo }
};
return new Promise(resolve => request(options, (error, response, body) => {
console.log('response received', response);
if(error) {
throw new Error(error);
}
resolve(body);
}));
}
async function getData() {
const result = [];
for(let i = 1, hasMorePages = true; hasMorePages; i++) {
const body = await getPage(i);
result.push(body);
hasMorePages = body.hasMorePages;
}
return result;
}
getData().then(data => console.log('RESULT', data));

Resources