0

I am writing a function calling an API to fetch URLs. These are the steps that I wish to accomplish:

  1. Parsing in an array of objects (restaurants) as arguments
  2. For each object, call the Google Search API to get some imageURLs
  3. Store those imageURLs in an array
  4. Add imageURLs as an attribute called imageURLs to each object within the array in the argument

The code is able to log the imageURLs within the GET request, but outside of the request, imageURLs is just an empty array.

var googleSearch = function(restaurants, cb){   
        console.log("google starts");   
        const apiKey = google_apiKey;   
        const cseKey = cseID;

         Array.from(restaurants).forEach(function(restaurant){   

    var keyWord = restaurant.name + " "+ restaurant.location.city
      + " "+ restaurant.location.state + " food";

    var googleURL = "https://www.googleapis.com/customsearch/v1?key="+ apiKey +
      "&q="+ keyWord +
      "&searchType=image" +
      "&cx=" + cseKey +
      "&num=7" +
      "&safe=medium"
    ;

    //image URLs of each restaurants to be displayed in the front end   
  var imageURLs = [];

  request
      .get(googleURL,
        {
          json : true, headers: {
            'User-Agent' : 'thaorell'
          }
        })
      .then(function(response){
          Array.from(response.items).forEach(function(item){
            imageURLs.push(item.link)
          });
        })
      .catch(e => {
        console.log(e);
      })
      restaurant.imageURLs = imageURLs
   })   
 cb(null, restaurants);
}
3
  • 1
    You're using an asynchronous API and calling cb before you finish the requests. You should put your cb call into your last .then from the chain. Commented Apr 23, 2018 at 21:18
  • Shouldn't the cb be after the request? Why does it get called before the request is finished? Commented Apr 23, 2018 at 21:22
  • Asynchronous means "without respect to timing" which mean that time is irrelevant to when the rest of the function if run Commented Apr 23, 2018 at 21:25

1 Answer 1

1

You're misunderstanding the Promise API:

var googleSearch = function (restaurants, cb) {
  console.log("google starts");
  const apiKey = google_apiKey;
  const cseKey = cseID;

  return Promise.all(Array.from(restaurants).map(function (restaurant) {

    var keyWord = restaurant.name + " " + restaurant.location.city
      + " " + restaurant.location.state + " food";

    var googleURL = "https://www.googleapis.com/customsearch/v1?key=" + apiKey +
      "&q=" + keyWord +
      "&searchType=image" +
      "&cx=" + cseKey +
      "&num=7" +
      "&safe=medium"
      ;

    return request
      .get(googleURL,
        {
          json: true, headers: {
            'User-Agent': 'thaorell'
          }
        }
      )
      .then(function (response) {
        restaurant.imageURLs = Array.from(response.items).map(function (item) {
          return item.link;
        });
        return restaurant;
      })
    })
  )
    .then(restaurants2 => cb(null, restaurants2))
    .catch(cb)
}

As you can see you need to wait for all of the requests to finish before you pass the data back to the callback.

Sign up to request clarification or add additional context in comments.

10 Comments

It returned an empty object. Is there another way to wait for the all the requests to execute?
Whoops! I did in fact do something bad. I misread a line in the fixing of it. Give me a moment. Okay I changed the forEach(no return) to a map(makes an array) which should now make it so that restaurant should have an array on it
Updated with another missing return. @CharlesThao can I ask for a little more clarification by what you mean with an empty object?
the cb at the end, aka restaurants2 returns {}
Without seeing more code I wouldn't be able to try and help farther. All I did was correct the promise order of your data returns to make sure that when it called the Callback it would wait for all data to load, associate the image urls onto the restaurant, and return a list of restaurants
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.