Reputation: 2318
Following is what I'm trying to do this in nodejs. The Rest API takes a city name as an input. I am trying to get the latitude and longitude using the geocode API for the input city. then, using the latitude and longitude, I am trying to get a list of closest cities using another API. then, for all those cities, I am getting the weather report, then for those cities, I am getting whether there is water and I am returning this back as a JSON.
As you can see, there is a lot of then and the goal of this exercise is to avoid nested callbacks.
I am using async/await which is supposed to have eliminated the nested then functions. But I don't see another way of doing this. The complete code snippet is below. The ugly part I am trying to fix is requester.makeRequest()
Following is just a snippet of the necessary code and not the complete working code. Any help on how to untangle this would be greatly appreciated.
app.get('/search', function(req, res, next) {
const requester = {
lastRequest: new Date(),
makeRequest: async function(url) {
const response = await fetch(url);
const json = await response.json();
return json;
}
};
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token)
.then(function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long)
.then(function(closer_cities) {
var cities_len = closer_cities.length
for(i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
requester.makeRequest(woeid_url + woeid)
.then(function(weather) {
var lattlong = weather.latt_long;
requester.makeRequest(onwater_url+ lattlong +
'?access_token=' + water_access_token)
.then(function(onwater) {
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({error: false,
data: {message: final_result}})
}
})
})
}
})
})
})
Upvotes: 2
Views: 1183
Reputation: 17711
When calling async
functions you are not supposed to use .then(...)
construct...
Simply let result = await myAsynchronousFunction(a, b, c);
...
Upvotes: 1
Reputation: 17654
for this line : requester.makeRequest ... .then(function(city){
replace .then(function(city){
with var city = await requester.makeRequest
, city
will have the fulfilled value of the promise, do this for the rest of then
s :
( keep in mind that await
is only used inside an async
function, you can use an iife )
(async () => {
var city = await requester.makeRequest(`${geocode_url}?locate=${req.query.q}&json=1${geocode_token}`);
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
var closer_cities = await requester.makeRequest(`${metaweather_url}?lattlong=${lat},${long}`);
var cities_len = closer_cities.length;
for (i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
var weather = await requester.makeRequest(woeid_url + woeid);
var lattlong = weather.latt_long;
var onwater = await requester.makeRequest(`${onwater_url}${lattlong}?access_token=${water_access_token}`);
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({
error: false,
data: {
message: final_result
}
})
}
}
})();
Upvotes: 1
Reputation: 222493
then
is misused in the first place because it results in callback hell. Promises are callback-based but they support chaining which is supposed to eliminate nested callbacks.
It should be:
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1` + geocode_token)
.then(function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
return requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long)
})
.then(function(closer_cities) {
...
});
If there's a promise inside then
, it should be returned. This way there's no more than a single level of callback nesting.
await
is syntactic sugar for then
, and rejections should be handled as well:
app.get('/search', function(req, res, next) {
try {
...
const city = await requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token);
var final_result = []
var lat = city.latt;
var long = city.longt;
const closer_cities = await requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long);
...
} catch (err) {
next(err)
}
});
Upvotes: 1
Reputation: 53
I would say you still need one then
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token)
.then(async function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
closer_cities = await requester.makeRequest(metaweather_url + '?lattlong='+ lat + ',' + long);
var cities_len = closer_cities.length;
for(i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
weather = await requester.makeRequest(woeid_url + woeid)
var lattlong = weather.latt_long;
onwater = await awaitrequester.makeRequest(onwater_url+ lattlong + '?access_token=' + water_access_token)
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({error: false, data: {message: final_result}})
}
}
})
Edit: I don't really think my answer is relevant for your problem sorry
Upvotes: 2