Cannot make React axios work when doing two GETs in a row

124 views Asked by At

I am working with OpenWeatherMap in order to grab the current weather of, say, Helsinki.

My latest MNWE (N as non) is:

import axios from 'axios'

const apiKey = import.meta.env.VITE_OWM_API_KEY

const getCityCoordinatesApiUrl = (city) => {
    return `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`
}

const getCityWeatherApiUrl = (longitude, latitude) => {
    return `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}`
}

const getCityWeather = (city, weatherJsonContainer) => {
    const url = getCityCoordinatesApiUrl(city)
    let longitude = null
    let latitude = null

    axios.get(url).then(response => {
        console.log("Hell", response.data)
        longitude = response.data.coord.lon
        latitude = response.data.coord.lat
    })
    .catch(error => {
        console.log("Error in getCityWeather:", error)
        alert(`Could not obtain weather of ${city}!`)
    })

    console.log("getCityWeather: received:", latitude, longitude)

    const url2 = getCityWeatherApiUrl(longitude, latitude)

    const outData = axios.get(url2).then(response => response.data)
    
    console.log("getCityWeather: outData:", outData)
}

My problem is that longitude and latitude stay as null. How can I resolve this issue? I have been working on it for several hours now.

Edit 1

After trying code kindly provided by urchmaney, my problematic implementation transforms into the following:

import axios from 'axios'

const apiKey = import.meta.env.VITE_OWM_API_KEY

const getCityCoordinatesApiUrl = (city) => {
    return `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`
}

const getCityWeatherApiUrl = (longitude, latitude) => {
    return `https://api.openweathermap.org/data/2.5/onecall?lat=${latitude}&lon=${longitude}&appid=${apiKey}`
}

const getCityWeather = (city) => {
    const url = getCityCoordinatesApiUrl(city)

    axios.get(url).then(response => {
        const longitude = response.data.coord.lon
        const latitude = response.data.coord.lat
        const url2 = getCityWeatherApiUrl(longitude, latitude)
        return axios.get(url2);
    })
    .then(response => {
        console.log(response.data)
        return response.data
    })
    .catch(error => {
        console.log("Error in getCityWeather:", error)
        alert(`Could not obtain weather of ${city}!`)
    })
}

export default {
    getCityWeather
}

(Calling the above)

const weatherJsonData = weatherService.getCityWeather('Helsinki')

Now, my problem is in the 2nd then: return response.data returns undefined.

3

There are 3 answers

0
eamanola On

you need to wait for 1st request to finish. Put the code after .catch() in a .then() statement

3
urchmaney On

You need to chain the API calls. The way you are trying to access the longitude and latitude is not in the right context. the assignment line console.log("getCityWeather: received:", latitude, longitude) is ran before the API call is returned.

To chain the API call you will do like this

    axios.get(url).then(response => {
        console.log("Hell", response.data)
        longitude = response.data.coord.lon
        latitude = response.data.coord.lat
        console.log("getCityWeather: received:", latitude, longitude)
        const url2 = getCityWeatherApiUrl(longitude, latitude)
        return axios.get(url2)
    })
     .then(res => {
      console.log("getCityWeather: outData:", res.data)
    })
    .catch(error => {
        console.log("Error in getCityWeather:", error)
        alert(`Could not obtain weather of ${city}!`)
    })

Async / Await Implementation


const getCityWeather = async(city) => {
   try {
      const response = await axios.get(url)
      const longitude = response.data.coord.lon
      const latitude = response.data.coord.lat
      const url2 = getCityWeatherApiUrl(longitude, latitude)
      return axios.get(url2)
   }
   catch (error) {
      console.log("Error in getCityWeather:", error)
      alert(`Could not obtain weather of ${city}!`)
   }
}

Remember it is an async method so you need to await it when consuming it

const weatherJsonData = await weatherService.getCityWeather('Helsinki')
2
Kabileesh G On

Send the city, lat, lon, appid as query params. I have altered the api call url based on this docs.

Try using async-await for better promises handling.

const url = "https://api.openweathermap.org/data/2.5/weather"

const getCityWeather = async(city) => {
try {
  const response = await axios.get(url, {
    params: {
      q: city,
      appid: apiKey,
    },
  });
  console.log(response);
  const longitude = response.data.coord.lon;
  const latitude = response.data.coord.lat;
  const response2 = await axios.get(url, {
    params: {
      lat: latitude,
      lon: longitude,
      appid: apiKey,
    },
  });
  console.log(response2);
  return response2.data;
} catch (err) {
  alert(`Could not obtain weather of ${city}!`);
  console.log(err);
}

I have removed the two functions as the urls are same and sent the data using axios params. This will resolve the issue.

Using .then() and .catch():

Changes in your code:

axios.get(url).then(response => {
    const longitude = response.data.coord.lon
    const latitude = response.data.coord.lat
    const url2 = getCityWeatherApiUrl(longitude, latitude)

    // response need to be caught by .then() as a callback. It should not be returned.
    axios.get(url2).then(response => {
         console.log(response.data)
         return response.data
    }).catch((error) => {
         console.log("Error in getCityWeather:", error)
         alert(`Could not obtain weather of ${city}!`)
    })
})
.catch((error) => {
    console.log("Error in getCityWeather:", error)
    alert(`Could not obtain latitude and longitude of ${city}!`)
})