Awaiting coordinates from geocoding google maps API returns pending promise - node.js

I am trying to return coordinates of given adress with gooogle maps geocoding API and fetch. I am able to log these coordinates inside my get fuction, but I have no idea how to return them from the function to use it somewhere else in the code. Already tried multiple varaitions of two approaches:
function getCoordinates1(name) {
locObj = fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${name}&key=mykey`).then( (res) => res.json()).then( (data) =>
{
console.log(data.results[0].geometry.location);
return data.results[0].geometry.location;
}).then((res) => res);
}
let coordinates1 = getCoordinates1(latinaze(name2));
console.log(coordinates1);
async function getCoordinates2(name) {
locObj = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${name}&key=mykeyk`).then( (res) => res.json()).then( (data) =>
{
console.log(data.results[0].geometry.location);
//return data.results[0].geometry.location;
}).then((res) => res);
return locObj
}
let coordinates2 = await getCoordinates2(latinaze(name2));
console.log(coordinates2);
First function returns undefined, second returns pending promise. What am I doing wrong?

The first function returns undefined because you don't return anything. As simple as that ;)
The second function returns a pending promise because you don't wait for the promise to be resolved. The promise gets resolved when the callback inside then is invoked, but that happens after you return locObj in getCoordinates2.
You should try this:
// function definition
async function getCoordinates3(name) {
const resp = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${name}&key=mykeyk`)
const data = await resp.json();
return data.results[0].geometry.location;
}
// usage
const coordinates3 = await getCoordinates3(latinaze(name3));

I couldn't return any value from function, so I made it a class method and set a property in function body. Now I can get the value form that property after I call the function:
export default class SearchModel {
constructor() {
this.start = '';
this.meta = '';
this.coors = [];
this.address = 'none';
}
//translate coordinates to address
async getAdress(coordinates) {
try {
let geocodeCoordinates = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${this.coors[0]},${this.coors[1]}&key=${process.env.API_GM_KEY}`
const rawData = await fetch(geocodeCoordinates);
//console.log(await rawData.json());
return await rawData.json();
} catch (error) {
return new Error(`Wild ERROR occured, can't get LocObj. Details: ${error}`);
} }
async displayAdress(coordinates) {
const data = await this.getAdress(coordinates);
const dataAdress = await data.results[0].formatted_address;
this.address = await dataAdress; }
}

Related

Await doesn't wait for the function to end + Node.js

I'm new to Node.js and was trying to get a lease from azure blob.
const leaseID = await acquireLease(container,blobName);
const result = await download(blob);
and acquireLease method is
const acquireLease = async function(container,blobName){
var leaseID;
blobService.acquireLease(container,blobName ,function(error,result,response){
if(!error) {
// Got lease
leaseID = result.id;
}
})
return(leaseID);
}
exports.acquireLease = acquireLease;
but before the acquireLease method gets completed and leaseID is got, the next main method
const result = await download(blob);
gets executed.
I tried promises but couldn't succeed.
const acquireLease = async function(container,blobName){
var leaseID;
return new Promise((resolve,reject)=>{
blobSvc.acquireLease(container,blobName ,function(error,result,response){
if(!error) {
// Got lease
leaseID = result.id;
}
})
resolve(leaseID);
})
}
exports.acquireLease = acquireLease;
Any suggestions or help appreciated.
You were really close with your Promise version! You just need to call resolve and reject at the right times.
Presumably, if error is truthy, then you should reject. Otherwise, it's safe to assume your result is valid and you can resolve the promise with result.id. There is no need for a leaseID variable. Also, if the function just returns a Promise, there's no need to mark it async.
const acquireLease = function (container, blobName) {
return new Promise((resolve, reject) => {
blobSvc.acquireLease(container, blobName, function (error, result, response) {
if (error) {
reject(error)
} else {
resolve(result.id)
}
})
})
}
exports.acquireLease = acquireLease;

Async/await function is returning "undefined" instead of expected String value

I am trying to learn how to work with async functions. I have my code below. There are two functions. The first, apiAddTask, calls the second function SchedulesDAO.GetScheduleByTitle. Both functions are static async functions and 'await' is used when calling the GetScheduleByTitle function.
In the GetScheduleByTitle function, I grab the needed ID from a Mongo Database. The function is correctly grabbing the ID, but is not returning it. Instead it returns undefined.
apiAddTask function:
static async apiAddTask(req, res, next){
try{
let taskFrequency = null
const taskTitle = req.body.title
const taskRepeat = req.body.repeat
if (taskRepeat == true){
taskFrequency = req.body.frequency
}
const taskStart = req.body.startdate
const taskEnd = req.body.enddate
let taskSchedule = await SchedulesDAO.GetScheduleByTitle(req.body.schedule) //CALL TO GETSCHEDULESBYTITLE <--
console.log(taskSchedule) // THIS PRINTS UNDEFINED <------------
const addResponse = await SchedulesDAO.addTask(
taskTitle, taskRepeat, taskFrequency, taskStart, taskEnd, taskSchedule
)
res.json({status:"success"})
}catch(e){
res.status(500).json({error: e.message})
}
}
GetScheduleByTitle Function:
static async GetScheduleByTitle(title) {
let query = {title: title}
let idString = ""
let cursor
try{
cursor = await schedules.find(query)
}catch (e) {
console.error("Unable to issue find command: " + e)
return {schedule: []}
}
cursor.toArray(function(err, results){
console.log(results[0]._id.toString()) //THIS PRINTS THE RIGHT ID STRING <-------------
idString = results[0]._id.toString()
return idString
})
}
I haven't been able to figure out exactly what I am missing. Please let me know if it would be helpful to see any other code.
Most of your code is fine. The issue lies in the fact that you are using a callback within your GetScheduleByTitle function:
async function () {
cursor.toArray(function(err, results){
console.log(results[0]._id.toString()) //THIS PRINTS THE RIGHT ID STRING <-------------
idString = results[0]._id.toString()
return idString
})
// implicit return undefined
}
What is happening is that your cursor.toArray() is being called, as you expect, but it is then continuing execution onto the implicit undefined return. Your function returns undefined before any of the callback logic is even processed.
The way to fix this:
try {
const results = await cursor.toArray()
let idString = results[0]._id.toString()
return idString
} catch (err) {
console.trace(err)
throw new Error(err)
}
Use the asynchronous promise based method.
If one does not exist, you could create a wrapper for a callback only function like so:
const cursorToArray = async (cursor) => {
return new Promise((resolve, reject) => {
cursor.toArray(function(err, results){
if (results)
resolve(results)
else
reject(err)
})
})
}

Get back empty nodejs + firebase

Guys I need some help with a get return with node and firebase.
I get an empty array.
but in console.log inside foreach prints correct
[{cnpj: '03052164798-000179', Address: 'Av Duke of Caxias 99999', Name: 'Testing', Tel: '999999999'}]
getEmpresas() {
let empresas = []
firebase.firestore().collection('empresa').get().then(snapshot => {
snapshot.docs.forEach(empresa => {
empresas.push(empresa.data())
console.log(empresas)
});
})
return empresas
I think this is a question about async. You're not getting the data you expect in the return because that fires before the async request is made. You'd need something like:
const getEmpresas = async () => {
let empresas = []
const snapshot = await firebase
.firestore()
.collection('empresa')
.get();
snapshot.docs.forEach((empresa) => {
empresas.push(empresa.data());
});
return empresas;
};
As imjared said in his answer, the function returns before .get() gets executed because it is an asynchronous function
You will need to return the chain of firebase functions which will return a Promise
getEmpresas() {
return firebase.firestore().collection('empresa').get().then(snapshot => (
snapshot.docs.map(({ data }) => data())
))
}
Then to access the returned Promise use .then() on the Promise or await inside an async function
getEmpresas.then(empresas => console.log(empresas))
Or inside an async function
const main = async () => {
const empresas = await getEmpresas()
console.log(empresas)
}
main()

NodeJS Async / Await - Build configuration file with API call

I would like to have a configuration file with variables set with data I fetch from an API.
I think I must use async and await features to do so, otherwise my variable would stay undefined.
But I don't know how to integrate this and keep the node exports.myVariable = myData available within an async function ?
Below is the code I tried to write to do so (all in the same file) :
const fetchAPI = function(jsonQuery) {
return new Promise(function (resolve, reject) {
var reqOptions = {
headers: apiHeaders,
json:jsonQuery,
}
request.post(apiURL, function (error, res, body) {
if (!error && res.statusCode == 200) {
resolve(body);
} else {
reject(error);
}
});
});
}
var wallsData = {}
const fetchWalls = async function (){
var jsonQuery = [{ "recordType": "page","query": "pageTemplate = 1011"}]
let body = await utils.fetchAPI(jsonQuery)
let pageList = await body[0].dataHashes
for(i=0;i<pageList.length;i++){
var page = pageList[i]
wallsData[page.title.fr] = [page.difficultyList,page.wallType]
}
return wallsData
throw new Error("WOOPS")
}
try{
const wallsData = fetchWalls()
console.log(wallsData)
exports.wallsData = wallsData
}catch(err){
console.log(err)
}
The output of console.log(wallsData) shows Promise { <pending> }, therefore it is not resolved and the configuration file keep being executed without the data in wallsData...
What do I miss ?
Thanks,
Cheers
A promise is a special object that either succeeds with a result or fails with a rejection. The async-await-syntax is syntactic sugar to help to deal with promises.
If you define a function as aync it always will return a promise.
Even a function like that reads like
const foo = async() => {
return "hello";
}
returns a promise of a string, not only a string. And you need to wait until it's been resolved or rejected.
It's analogue to:
const foo = async() => {
return Promise.resolve("Hello");
}
or:
const foo = async() => {
return new Promise(resolve => resolve("Hello"));
}
Your fetchWalls similarly is a promise that will remain pending for a time. You'll have to make sure it either succeeds or fails by setting up the then or catch handlers in your outer scope:
fetchWalls()
.then(console.log)
.catch(console.error);
The outer scope is never async, so you cannot use await there. You can only use await inside other async functions.
I would also not use your try-catch for that outer scope promise handling. I think you are confusing the try-catch approach that is intended to be used within async functions, as there it helps to avoid nesting and reads like synchronous code:
E.g. you could do inside your fetchWalls defintion:
const fetchWalls = async function (){
var jsonQuery = [{ "recordType": "page","query": "pageTemplate = 1011"}]
try {
let body = await utils.fetchAPI(jsonQuery)
} catch(e) {
// e is the reason of the promise rejection if you want to decide what to do based on it. If you would not catch it, the rejection would chain through to the first error handler.
}
...
}
Can you change the statements like,
try{
const wallsData = fetchWalls();
wallsData.then((result) => {
console.log(result);
});
exports.wallsData = wallsData; // when importing in other file this returns as promise and we should use async/await to handle this.
}catch(err){
console.log(err)
}

nodejs promisify a callback function with one parameter /callback

util.promisify appears to always expect 2 parameters from a callback function, however the existing functions do not have a seperate callback for err and data, but only a single callback.
How can I handle this ???
const {promisify} = require('util');
function y(text,cb){
setTimeout(function(){cb({error:false,data:text})},1000);
}
async function test(text) {
try{
const z = promisify(y)
return await z(text);
} catch(e) {return {error:true,msg:e}}
}
console.log(test('xxx'));
What I am looking for is to return the value from function y syncronously and not getting a promise i.e.
var x = test('xxx');
Given the information in your comment, you can wrap the function with a compatible signature to be passed directly to promisify():
const { promisify } = require('util')
function y (query, callback) {
callback(query)
}
function yCompatible (query, callback) {
y(query, ({ error, data }) => {
callback(error && data, error || data)
})
}
const yAsync = promisify(yCompatible)
async function test (query) {
try {
return yAsync(query)
} catch (error) {
return error
}
}
test('xxx').then(
data => { console.log(data) },
error => { console.error(error) }
)
Also try not to get in the habit of using single letter variables like a mathematician ;) I realize this is just example code, but even then it's helpful to be a bit more explicit about your intent.

Resources