Wanderlust project - walkthrough final challenge with code snippets

Jokes aside, I spent more time figuring out the correct api call than the actual time spent coding.

This post is for those who had/are having issues with the final challenge of Wanderlust project.
What I did:

  • Stored in a global variable the venues ids
let venuesIds = [];
//get data from Foursquare
async function getVenues(){
  const city = $input.val();
  let limit = 10;
  const and = "&";
  const toFetch = url.toString()+city.toString()+and+"limit="+limit.toString()+and+"client_id="+clientId.toString()+and+"client_secret="+clientSecret.toString()+and+"v=20210421"; 
  try{
    const response = await fetch(toFetch);
    if(response.ok){
      const jsonResponse = await response.json();
      //obtaining array of venues from API response
      const venues = jsonResponse.response.groups[0].items.map(
        (item) => item.venue
      );
      //storing the id of each venue for a later request
      venues.forEach(
        venue => venuesIds.push(venue.id)
      );      
      // console.log(venues);
      // console.log(venuesIds);
      return venues;
    }
  }catch(error){
    console.log(error)
  }
};
  • Created an async function that would loop through the venues ids previously stored and store in a global variable the urls of the best photos for the various venues
let venuesImgs = [];
//get bestPhoto urls for each venue obtained with getVenues()
async function venuesPhotosUrl() {
  const and = "&";
  for await (const id of venuesIds) {
    const toFetch =  "https://api.foursquare.com/v2/venues/"+id.toString()+"?"+"client_id="+clientId.toString()+and+"client_secret="+clientSecret.toString()+and+"v=20210421";
    try{
      const response = await fetch(toFetch);
      if(response.ok){
        const jsonResponse = await response.json();
        console.log(jsonResponse);
        //obtain bestphoto
        const pathTobestPhoto = jsonResponse.response.venue.bestPhoto;
        console.log(pathTobestPhoto);
        const bestPhotoUrl = pathTobestPhoto.prefix.toString()+pathTobestPhoto.width.toString()+"x"+pathTobestPhoto.height.toString()+pathTobestPhoto.suffix.toString();
        console.log(bestPhotoUrl);
        venuesImgs.push(bestPhotoUrl);
      }    
    }catch(error){
      console.log(error)
    }      
  }
};

bestPhoto is a property available from the Premium API Endpoints details, as per their docs:

Photo we have determined to be the best photo for the venue based on user upvotes and our internal algorithm.

Because it’s a premium API it’s capped at 50 requests per day, so if you suddenly start getting an error in browser console with code 429, is because you reached the limit.

The weird const pathTobestPhoto = jsonResponse.response.venue.bestPhoto; instead of a simple and more obvious jsonResponse.bestPhoto is because the actual response received from the server is not the list of response fields as the documentation suggests, but instead:

{
  "meta": {
    //some stuff
  },
  "response": {
    //list of response properties as per https://developer.foursquare.com/docs/api-reference/venues/details/#response-fields
  }
}

So do not confuse the variable const response = await fetch(toFetch); with the property response of the object above (that is jsonResponse).

  • Finally, render the photos with renderVenues(venues) when is called from executeSearch()
// Render venues from getVenues()
const renderVenues = (venues) => {
  $venueDivs.forEach(($venue, index) => {
    const venue = venues[index];
    const venueIcon = Object.values(venue.categories[0].icon).join("bg_64");
    const bestPhotoUrl = venuesImgs[index];
    // console.log(venueIcon);
    let venueContent = createVenueHTML(venue.name, venue.location, venueIcon, bestPhotoUrl);
    $venue.append(venueContent);
  });
  $destination.append(`<h2>${venues[0].location.city}</h2>`);
};
//listen for submitted button
const executeSearch = () => {
  $venueDivs.forEach(venue => venue.empty());
  $weatherDiv.empty();
  $destination.empty();
  $container.css("visibility", "visible");
  Promise.all([getVenues(), venuesPhotosUrl()]).then(
    venues => renderVenues(venues[0])
  , error => console.log(error));
  getForecast().then(
    forecast => renderForecast(forecast)
  );
  return false;
};

Promise.all() returns an array of the values returned by each Promise it resolves, if all are fulfilled. Because venues in this case is an array we need to pass to renderVenues(passTheOutputOfGetVenues) only the first element of this array, which corresponds to the returned value of the first promise: getVenues().

  • Of course in helpers.js we also need to edit createVenueHTML()
    createVenueHTML = (name, location, iconSource, bestPhotoUrl)

What I learnt from this challenge is that working with APIs is stressful and that jQuery should not to be used anymore.

Hopefully this will be useful for someone, if you have any questions feel free to ask.
If anyone else got different ideas on how to solve this challenge share them! It’ll make great feedback :slight_smile: