I am trying to extract data from an Axios call in Javascript. I can see that the data is being called successfully if I console.log() while inside of this block
Here is a link to a screenshot of console.log() if it is inside the axios call. https://imgur.com/a/ZLXnE2n
This data is correct, but I can't access it outside of the axios call.
const response = await axios
.get(url, config)
.then(function(response) {
data = response.data;
console.log(data)
})
However, I am unable to do anything with the data outside of the getRide_Uber function. How do I extract the response object to use in other parts of my code?
const axios = require("axios");
// Use the Uber API to estimate the cost between two
// locations specified via latitude and longitude coordinates.
getRide_Uber = async (addressOrigin, addressDestination) => {
let origin = await geocodeAddress(addressOrigin);
let destination = await geocodeAddress(addressDestination);
const url = "https://api.uber.com/v1.2/estimates/price";
const config = {
headers: {
Authorization: `Token ${process.env.UBER_SERVER_TOKEN}`
},
params: {
start_latitude: origin.lat,
start_longitude: origin.lon,
end_latitude: destination.lat,
end_longitude: destination.lon
}
};
const response = await axios
.get(url, config)
.then(function(response) {
data = response.data;
return data;
})
.catch(function(error) {
console.log(error);
});
return response;
};
// Initial code
// const rideData = getRide_Uber("Arlington Texas", "Fort Worth Texas");
// const ridePrices = rideData.prices;
// console.log(ridePrices);
// Code suggestion by #mralanlee
const a = (async() => {
const result = await getRide_Uber(start, dest);
return result;
})();
console.log(a); // Console just says <pending>
const prices = a.prices // undefined
Please let me know if anything needs clarification and I will be happy to explain. Thanks!
The data store is back into getRide_Uber.
You can have it accessible or returned globally like:
(async() => {
const result = await getRide_Uber(start, dest);
// or console.log(result)
return result;
})()
or
const a = (async() => {
const result = await getRide_Uber(start, dest);
return result;
})();
For the above solution, you would need to have this in a scape of another async function. This will not work at the global level because logging the result will not wait for the Promise to resolve. You must wrap it into an async function and await the anonymous function.
Edit: Clarification to add more clarity...
To use the 2nd solution, you could do the following:
// this async function wraps around your code, we'll call it something for a lack of a better name
// start and dest params are passed into getRide_Uber
async function something(start, dest) {
const result = await getRide_Uber(start, dest);
// You can make sure you have the resolved data here.
// console.log(result.prices)
return result;
};
// now call the function
something(start, dest);
Related
I am working on a weather based API project to sharpen my skills, but while fetching data i am getting a error:
Uncaught (in promise) TypeError: result.main is undefined
here is the function responsible for fetching data from API:
async function fetchData(cityName) {
const API_KEY = 'MY_API_TOKEN';
const fetchRes = {
method: 'GET',
redirect: 'manual',
mode: 'cors',
};
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${API_KEY}`,
fetchRes
);
const result = await response.json();
const data = result.main.temp;
console.log(data);
}
fix using this call
fetchData("london");
here i am taking city name using another input and search button
note: i hide my API token key for Security Reasons so that's not the issue
separate effects
return the result instead of logging it -
async function fetchData(cityName) {
const API_KEY = 'MY_API_TOKEN';
const fetchRes = {
method: 'GET',
redirect: 'manual',
mode: 'cors',
};
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${API_KEY}`,
fetchRes
);
const result = await response.json();
return result.main.temp // <-- return the result
}
Now attach effect and error handler -
fetchData(...)
.then(console.log) // <- receives data
.catch(console.error) // <- receives error
You can attach both the effect and error handler in a single .then -
fetchData(...)
.then(console.log, console.error) // <- same behaviour as above
separate concerns
And I would recommend separating concerns to make it easier to read/write your functions -
const getJSON = (url, opts = {}) =>
fetch(url, opts).then(r => r.json())
Now you don't have to repeat yourself every time you want to query some JSON -
async function fetchData(cityName) {
const API_KEY = 'MY_API_TOKEN';
const url = `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${API_KEY}`
const opts = {
method: 'GET',
redirect: 'manual',
mode: 'cors',
};
const result = await getJSON(url, opts) // <- reusable function
return result.main.temp
}
URL handling
I would advise against building URLs using strings. Instead use the URL searchParams API to construct things programmatically -
async function fetchData(cityName) {
const API_KEY = 'MY_API_TOKEN'
// use URL api
const u = new URL("https://api.openweathermap.org/data/2.5/weather")
u.searchParams.set("q", cityName)
u.searchParams.set("appid", API_KEY)
const opts = {...}
const result = await getJSON(u, opts) // <- pass URL object
return result.main.temp
}
As you can see it would be annoying to have to write all of that each time you need to set/modify some URL parameters. Applying the lesson from above, we write href -
function href(url, params = {}) {
const u = new URL(u)
for (const [key, value] of Object.entries(params))
u.searchParams.set(key, value)
return u.toString()
}
Now you can avoid repetitive and error-prone code in common functions -
async function fetchData(cityName) {
const API_KEY = 'MY_API_TOKEN'
// use our href helper
const u = href("https://api.openweathermap.org/data/2.5/weather", {
q: cityName,
appid: API_KEY
})
// use getJSON helper
const result = await getJSON(u, {...})
return result.main.temp
}
fetchData("someCity").then(console.log, console.error)
i am a beginner in javascript async await function. I have tried to make a asynchronous request in my backend and i want it to initialized in my variable but when I tried to log my variable, it gives me a promise and not a value. When i also tried to put an await. It gives me error.
Here is what I've done:
const getActivityContestApi = async () => {
try {
const response = await fetch(
`${getDjangoApiHost()}/api/events/event_activity_contests/`, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
});
const data = await response.json();
return data;
} catch(error) {
console.log(error)
}
}
The function above is my asynchronous function, I want this to be stored in a variable like this:
const test_variable = getActivityContestApi();
console.log(test_variable);
this code gives me a promise. I want the actual variable so I tried to put await like this:
const test_variable = await getActivityContestApi();
console.log(test_variable);
this gives me error in react. please help.
await is only allowed inside async function.
const test_variable = await getActivityContestApi();
you can only use this statement inside another async function.
asyncFunction will return a promise. So if you just want get result, maybe you can use then
getActivityContestApi().then((resolve,reject)=>{
let test_variable = resolve;
console.log(test_variable);
})
await can't exist outside of async function. Here is what you need to do:
;(async () => {
const test_variable = await getActivityContestApi();
console.log(test_veriable);
})()
The 1st example logs the resolved value of the promise from the fetch.
The 2nd example logs the pending promise object to the console which I then have to .then((res) => {console.log(res)}) to get the resolved value.
I'm using async functions so I thought both examples were equivalent...?
I have not shown my API key but it works when I use it in the code.
1st Example:
const apiKey = 'somekey';
const city = 'Berlin'
const getWeather = async (cityArg, apiKeyArg) => {
let city = cityArg;
let apiKey = apiKeyArg;
try{
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`);
if(response.ok) {
let jsonResponse = await response.json();
console.log(jsonResponse);
//return jsonResponse;
}
} catch(error) {
console.log(error);
}
}
getWeather(city, apiKey);
//console.log(getWeather(city, apiKey));
2nd Example:
const apiKey = 'somekey';
const city = 'Berlin'
const getWeather = async (cityArg, apiKeyArg) => {
let city = cityArg;
let apiKey = apiKeyArg;
try{
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`);
if(response.ok) {
let jsonResponse = await response.json();
//console.log(jsonResponse);
return jsonResponse;
}
} catch(error) {
console.log(error);
}
}
//getWeather(city, apiKey);
console.log(getWeather(city, apiKey));
The reason is that you are awaiting inside that async function, but not in the console.log at the bottom.
Anything outside of that async is going to continue on running as normal. So the console.log(getWeather(city, apiKey) keeps running even though that function has not gotten a response yet. There are a few solutions. First, you could await getWeather, which requires wrapping it in a function.
await function secondFunc(){
console.log(await getWeather(city, apiKey));
}
secondFunc();
In my opinion, the better way is to use .then. I almost always use it, it is cleaner and more logical to me. Don't forget that you can chain promise statements.
fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`)
.then(response => response.json())
.then((response)=>{
console.log(response);
//Other code to do stuff with the response
})
.catch((error)=>{
console.log(error);
});
Another way to think of it is that the getWeather is Async, which will wait for a response, and return a promise in the meanwhile. But console.log is not async. So console.log keeps running as usual, but it has only recieved a Promise from getWeather, because that function is not resolved.
Hope that is clear. If you don't quite understand, let me know and I will do my best to explain further.
async functions return promises and since console.log isn't an async function it won't wait for getWeather() to resolve and will just log pending
hope that clears it up
id recommend just using .then()
//you could do
getWeather(city,ApiKey).then((response) =>{console.log(response));
hope that was helpful
I have an axios request file that goes and gets many requests which I used an async function around it all so that I could delay the requests per second sent to an api (their rate limit).
My code:
import axios from 'axios';
export const litecoinApi = async (addresses, resolve, reject) => {
let addressesBalance = {};
let addressRequests = [];
addresses.forEach(address => {
addressRequests.push("https://api.blockchair.com/litecoin/dashboards/address/" + address);
});
function delay() {
return new Promise(resolve => {
setTimeout(() => resolve(), 2000);
});
}
let i;
for (i = 0; i < addressRequests.length; i++) {
await axios.get(addressRequests[i])
.then((res) => {
console.log(res.data.data);
const data = res.data.data[addresses[i]];
console.log('data', data.address.balance);
addressesBalance[addresses[i]] = data.address.balance / 100000000;
}).catch((error) => {
console.log(error);
});
await delay();
}
resolve(addressesBalance);
// let i;
// for (i = 0; i < addressRequests.length; i++) {
// await axios.get(addressRequests[i])
// .then((res) => {
// const data = res.data.data;
// console.log(data);
// addressesBalance[data.address.toString()] = data.confirmed_balance.toString();
// }).catch((err) => {
// console.log(err.response);
// });
// await delay();
// }
// resolve(addressesBalance);
};
I am simply accessing the request and going through the object to receive the (address balance).
I am getting the warning in the console:
./src/apis/litecoin.js
Line 20: Don't make functions within a loop no-loop-func
The problem I'm having is that line 20:
.then((res) => {
Is actually not the problem, it is clearly line 22:
const data = res.data.data[addresses[i]];
addresses is simply an array of strings. When I remove accessing the key addresses[i] from the object res.data.data the warning goes away. The object res.data.data in console is:
{LWcXUB6ny88tK49TK1V6KprE5oDcJ1zJhx: {…}}
LWcXUB6ny88tK49TK1V6KprE5oDcJ1zJhx:
address:
{type: null, script_hex: "", balance: 0, balance_usd: 0, received: 0, …}
transactions:
[]
So the litecoin address LWcXUB6ny88tK49TK1V6KprE5oDcJ1zJhx is the key in an object and the value is another object with address and transactions as keys. My final goal is the balance in the value of the address key.
I left a commented for loop below (which was for a slightly different api) because I don't get the warning in that one. The problem is there is simply no way to access the value of the litecoin address key without how you would normally access a key in an object.
I have changed this line:
const data = res.data.data[addresses[i]];
To:
const data = res.data.data;
const address = Object.keys(data);
As soon as I attempt Object.keys I get the error let alone actually accessing the first key:
address[0]
This leaves me at a complete loss because then I literally can't access the object without getting the error that I am using a loop in a function.
The resolve and reject are from a promise that this function gets called in and I use the async function to wait until all the api requests are done before I resolve the promise that this function is in.
That promise then goes out and sets my state correctly.
Anyone have any ideas? I have looked at many other SO however no one seems to be dealing with the problem I am here. I honestly don't see how I am using a function at all in the loop.
Accessing a key in an object certainly isn't a function that I know.
The:
.then((res) => {
...
}
Is simply waiting for the axios.get promise. This get / then cycle has worked in other api requests without this issue. Plus the warning really only happens when attempting to pass a key into an object inside the for loop.
I should let you know everything works correctly with the warning. It just infuriates me that I can't get rid of this warning.
Thank you very much for your time and insight.
You can try something simple and single process at the time:
import axios from 'axios';
export const litecoinApi = async (addresses) => {
const balance = {};
for (const address of addresses) {
const currentAddress = `https://api.blockchair.com/litecoin/dashboards/address/${address}`;
const result = await axios.get(currentAddress)
const data = result.data.data[address];
console.log(data);
balance[address] = data.address.balance / 100000000;
}
return balance;
}
Or you can process all requests in parallel with:
const result = await Promise.all(promises);
On the advice of Teemu ( if you want to re-post this answer i'll give you the answer ).
I tried this:
import axios from 'axios';
export const litecoinApi = async (addresses, resolve, reject) => {
let addressesBalance = {};
let addressRequests = [];
addresses.forEach(address => {
addressRequests.push("https://api.blockchair.com/litecoin/dashboards/address/" + address);
});
function delay() {
return new Promise(resolve => {
setTimeout(() => resolve(), 2000);
});
}
function axiosRequest(addressRequests, addresses) {
axios.get(addressRequests)
.then((res) => {
console.log(res.data.data);
const data = res.data.data[addresses];
console.log('data', data.address.balance);
addressesBalance[addresses] = data.address.balance / 100000000;
}).catch((error) => {
console.log(error);
});
}
let i;
for (i = 0; i < addressRequests.length; i++) {
await axiosRequest(addressRequests[i], addresses[i]);
await delay();
}
resolve(addressesBalance);
};
Which simply moves the axios request into its own function that is then passed the requests and addresses.
The await cannot work within the axiosRequest() function but you can still use it in the for loop solving the problem.
This solved my problem thank you very much Teemu!
Please, how can I save output of fetch to a variable - to be able to work with it as with an object?
Here is the code:
var obj;
fetch("url", {
method: "POST",
body: JSON.stringify({
"filterParameters": {
"id": 12345678
}
}),
headers: {"content-type": "application/json"},
//credentials: 'include'
})
.then(res => res.json())
.then(console.log)
The final console.log will show an object. But when I tried to save it to variable .then(res => obj = res.json()) than the console.log(obj) will not hold the Object, but the Promise.
Any idea please, how to turn it into an Object saved in the variable?
.json() is an async method (it returns a Promise itself), so you have to assign the parsed value in the next .then()
var obj;
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(res => res.json())
.then(data => {
obj = data;
})
.then(() => {
console.log(obj);
});
Modern async/await equivalent
You have to await the .json() method.
async function foo() {
let obj;
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1')
obj = await res.json();
console.log(obj)
}
foo();
Instead of storing in a variable, create a function that will return data, and then store it in a variable. So It can accessible in your whole file.
async function fetchExam(id) {
try {
const response = await fetch(`/api/exams/${id}`, {
method: 'GET',
credentials: 'same-origin'
});
const exam = await response.json();
return exam;
} catch (error) {
console.error(error);
}
}
Then call that function to get data
async function renderExam(id) {
const exam = await fetchExam(id);
console.log(exam);
}
Update
With the current version of Node.js v14.3.0 support Top-Level async-await
import axios from 'axios';
const response = await axios('https://quote-garden.herokuapp.com/api/v3/quotes/random');
console.log(response.data);
Running this file using node --harmony-top-level-await top-level-async-await.js
Output
More details: https://medium.com/#pprathameshmore/top-level-await-support-in-node-js-v14-3-0-8af4f4a4d478
You can do like this. First fetch the data and create a function to do something with the data.
And then pass the result to that function and access it anywhere.
fetch('https://pokeapi.co/api/v2/pokemon/ditto')
.then(jsonData => jsonData.json())
.then(data => printIt(data))
let printIt = (data) => {
console.info(typeof data)
}
let data = [];
async function getRandomUser(){
// gets the response from the api and put it inside a constant
const response = await fetch('https://randomuser.me/api');
//the response have to be converted to json type file, so it can be used
const data = await response.json();
//the addData adds the object "data" to an array
addData(data)
}
function addData(object) {
// the push method add a new item to an array
// here it will be adding the object from the function getRandomUser each time it is called
data.push(object);
//the fetched data is available only on this scope
console.log("This is the value of date inside the function addData:")
console.log(data)
}
//Calls the function that fetches the data
getRandomUser()
console.log("This is the value of data outside the scope")
console.log(data)
A simple and handy solution is :
function myFunc(success) {
//do what you want HERE.
console.log(success)
}
fetch('https://reqres.in/api/users?page=2')
.then(data => data.json())
.then(success => myFunc(success));
Easiest approach is to use async/await method.
Simply copy & paste the following code in your chrome dev console to see the magic:
async function githubUsers() {
let response = await fetch('https://api.github.com/users')
let users = await response.json()
console.log(users)
}
githubUsers()