I have a function that calls an API and returns some data:
async function getDataAxios(){
await axios.get("http://localhost:8080/cards/1").then(response => {
console.log("RESP: ", response.data[0])
return response
})
.catch(err => {
console.log("Error: ", err)
return err
})
}
When I log response.data[0] inside getDataAxios() the expected data is present.
But when I try and return the data to my calling function and log the return data it logs undefined:
getDataAxios().then(r => console.log(r))
I have also tried the following:
const resp = getDataAxios().then(resp => console.log("Data 2: ", resp)).catch(
err => {
console.log("An error has occurred: ", err)
return err;
}
)
console.log(resp)
Full code:
function App() {
getDataAxios().then(r => console.log(r))
}
async function getDataAxios(){
await axios.get("http://localhost:8080/cards/1").then(response => {
console.log("RESP: ", response.data[0])
return response
})
.catch(err => {
console.log("Error: ", err)
return err
})
}
export default App;
Just adding here some more details, since the comment was not very detailed.
You have
async function getDataAxios(){
await axios.get(...).then(...).catch(...);
}
and
function App() {
getDataAxios().then(r => console.log(r))
}
The getDataAxios method does not return anything. The then inside it does return a value, but that is not returned from the actual getDataAxios function.
Nothing wrong with that on its own, if the then code is all you wanted to perform.
But you then call it in the App and use then on it, getDataAxios().then(r => console.log(r)). The r here will contain whatever was returned from the getDataAxios which is nothing, so the r will be undefined.
Adding the return to the getDataAxios will return the promise. And since the return value type of axios is a promise you do not have to specify async, nor await for it.
So you can use
function getDataAxios(){
return axios.get(...).then(...).catch(...);
}
and now you can use it as you already do, as
function App() {
getDataAxios().then(r => console.log(r))
}
Turn the response into a constant and than store data in it and than return it. Do this instead.
async function getDataAxios(){
await axios.get("http://localhost:8080/cards/1").then(response => {
console.log("RESP: ", response.data[0])
const response = response.data[0]
return response
})
.catch(err => {
console.log("Error: ", err)
return err
})
}
Or you can do this
async function getDataAxios(){
await axios.get("http://localhost:8080/cards/1").then(response => {
console.log("RESP: ", response.data[0])
return response.data[0]
})
.catch(err => {
console.log("Error: ", err)
return err
})
}
Related
I am writing a helper for my API calls and would like it to
pass a text() response when the call is successful
throw the full Response otherwise
The reason for this is that I have a case of an API call where a 404 is expected and would like to manage this specific case. Other 404 (in different calls) are indeed errors.
Consider the code below:
const apiCall = (url) => {
return fetch(url)
.then(r => {
if (r.ok) {
return r.text()
} else {
console.log('in apiCall → then(), fetch soft-failed, passing error downstream')
throw Error(r.statusText) // this works but is not what I want, I want to throw "r"
}
})
.catch(err => {
console.log('in apiCall → catch(), passing error downstream')
throw err
})
}
apiCall('http://httpstat.us/200')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err}`))
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err}`)) // this works but I obviously got a statusText and not an r
This outputs
in apiCall → then(), fetch soft-failed, passing error downstream
in apiCall → catch(), passing error downstream
the return code was Error: Not Found
200 OK
What I would like to do is for one call where the 404 is expected (this is incorrect code in the context of the code above)
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => {
if (err.Code == 404) {
// it is OK
} else {
// it is not OK
}
})
and for another call where any non-2xx response is incorrect :
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => {
// not OK
})
How can I throw the Response and not only text?
In other words, the code I would like to have:
const apiCall = (url) => {
return fetch(url)
.then(r => {
if (r.ok) {
return r.text()
} else {
console.log('in apiCall → then(), fetch soft-failed, passing error downstream')
throw r
}
})
.catch(err => {
console.log('in apiCall → catch(), passing error downstream')
throw err // I would need to manage actual errors (network, ...)
})
}
apiCall('http://httpstat.us/200')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err.Code}`))
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err.Code}`))
but this outputs undefined
in apiCall → then(), fetch soft-failed, passing error downstream
in apiCall → catch(), passing error downstream
the return code was undefined
200 OK
You can add an argument as expectedFailureCodes and check the request code after it fails. If it is well expected then you can handle it as you like.
import fetch from "node-fetch";
const apiCall = (url, expectedFailureCodes=[]) => {
return fetch(url)
.then(async res => {
if (res.ok) return res
else if (expectedFailureCodes.includes(res.status)) {
return {
passedIntentionally: true,
res
}
}
else throw new Error(JSON.stringify({
status: res.status,
body: await res.text()
}))
})
.catch(err => {
throw err
})
}
apiCall("http://httpstat.us/404", [404]).then(res => {
console.log(res)
})
apiCall("http://httpstat.us/404", ).catch(err => {
console.log(err)
})
apiCall("http://httpstat.us/200", ).then(res => {
console.log(res)
})
Well, throwing r works fine, you were just logging the wrong property. The status code can be accessed via r.status:
const apiCall = (url) => {
return fetch(url)
.then(r => {
if (r.ok) {
return r.text()
} else {
console.log('in apiCall → then(), fetch soft-failed, passing error downstream')
throw r
}
})
.catch(err => {
console.log('in apiCall → catch(), passing error downstream')
throw err // I would need to manage actual errors (network, ...)
})
}
apiCall('http://httpstat.us/200')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err.status}`))
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => console.log(`the return code was ${err.status}`))
The only problem with that approach is, that your code won't know how to handle "hard errors" (network errors or runtime errors in the code). You can identify those with "duck typing methods" (if it has a status property, it must be a Response object...), but a better solution would be to have a custom Error class:
class HTTPError extends Error{
constructor(r){
super(`HTTP ${r.status} error`)
this.r = r
}
}
const apiCall = (url) => {
return fetch(url)
.then(r => {
if (r.ok) {
return r.text()
} else {
console.log('in apiCall → then(), fetch soft-failed, passing error downstream')
throw new HTTPError(r)
}
})
.catch(err => {
console.log('in apiCall → catch(), passing error downstream')
throw err
})
}
apiCall('http://httpstat.us/200')
.then(r => console.log(r))
.catch(err => {
if(!(err instanceof HTTPError))
throw err //Other error
console.log(`the return code was ${err.r.status}`)
})
apiCall('http://httpstat.us/404')
.then(r => console.log(r))
.catch(err => {
if(!(err instanceof HTTPError))
throw err //Other error
//You can access `r` via `err.r` here
console.log(`the return code was ${err.r.status}`)
})
I'm new to all this export, import, async so please bare with me.
I have one file where I make API call and export that function so it can be used across other pages.
Of course on other page when function is invoked data payload is not yet there so i get undefind. So i tried to implement async (first time).
Please correct me if this is even possible or I I need some other method.
app.js:
export function inboxMeniIkona () {
//let req = xxxx
fetch(req)
.then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error('NETWORK RESPONSE ERROR')
}
})
.then(data => {
return new Promise(resolve => {
return data // data here is allright
});
})
.catch(error => console.error('FETCH ERROR:', error))
}
And then I tried on other page:
import { inboxMeniIkona } from '~/app'
async function asyncCall() {
console.log('calling');
const result = await inboxMeniIkona();
console.log(result);
// expected output: "resolved"
}
asyncCall();
I'm still getting
CONSOLE LOG: calling
CONSOLE LOG: undefined
Please advise
Add async in your functions and await in your fecth and return it like this.
export async function inboxMeniIkona () {
//let req = xxxx
return await fetch(req)
.then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error('NETWORK RESPONSE ERROR')
}
})
.then(data => {
return data // data here is allright
})
.catch(error => console.error('FETCH ERROR:', error))
}
Im getting this error:
TypeError: Cannot read property 'then' of undefined in controller
[controller]
fetchGameData() {
DataModel.getList().then(data => {
console.log(data);
})
}
[DataModel]
export default {
getList() {
fetch('URL')
.then((res) => {
return Promise.resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
})
}
}
The error is already clear actually. Your function getList() does not return anything which is going to be undefined in JavaScript. You should return "something" at the end of your function. If you want to use .then on the return value of your function, you probably want to return a "Promise"
fetch function will return a Promise anyway. So can simply return that. You can find more info about fetch here https://javascript.info/fetch
So a neater alternative would be
export default {
getList() {
return fetch('URL')
.then((res) => {
return Promise.resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
})
}
}
You need to return a promise to do .then
export default {
getList() {
return new Promise((resolve, reject) => {
fetch("URL")
.then((res) => {
resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
});
});
},
};
[Service]
async function getList() {
const result = await fetch('URL')
.then((res) => {
return Promise.resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
})
return result.json();
}
[controller]
fetchGameData() {
DataModel.getList().then(data => {
console.log(data);
})
}
You are getting that error because the DataModel.getList() doesn't return a Promise so you can have access to Promise then chain. All you have to do is to add a return keywork in the getList before the fetch function so the getList method can return a resolve Promise instead of undefined
export default {
getList() {
return fetch('URL')
.then((res) => {
return Promise.resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
});
}
}
You should return the promise inside your getList() function.
otherwise a function with no return will return undefined.
And this you will have the error "...cant read then of undefined"
your code should be :
export default {
getList() {
return fetch('URL')
.then((res) => {
return Promise.resolve(res.json());
})
.catch((err) => {
console.log("Fetch Error!!!", err);
})
}
}
this is my code:
export async function fetchData(searchValue) {
await fetch(`https://api.edamam.com/search?q=${searchValue}&app_id=${apiId}&app_key=${apiKey}`)
.then(res => res.json())
.then(
(result) => {
return result;
},
(error) => {
return (`Error: ${error}`);
}
)
}
The issue is:
I can't return the result to other component, but if I logged that value into the console, I can see the value, any help?
If I return the statement "await fetch" I can console log the object but I don't know how to access the data you can see on this image
Write your function like this:
export async function fetchData() {
try {
const response = await fetch(
`https://api.edamam.com/search?q=${searchValue}&app_id=${apiId}&app_key=${apiKey}`
);
return await response.json();
} catch (err) {
console.log(`Error: ${error}`);
}
}
I am new in JavaScript and I have a problem:
I do fetch('path'), then I assign values and return it. Later I call this function in my other functions but it runs first with empty values without waiting values to be assigned. How can I solve this? I think I should use async and await but do not know exactly how.
function loadLocalJson(path) {
let users = [];
fetch(path)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok :(');
}
return response.json();
})
.then(results => {
users = results
console.log(users);
})
.catch(err => console.log('Error', err));
return users;
}
function getFilteredAndSortedArray(users, price) {
console.log(users, price);
return users.filter(user => {
return user.salary && user.salary > price;
})
.sort(user => user.name);
}
users = loadLocalJson('users.json');
usersB= getFilteredAndSortedArray(users, 1000);
console.log(usersB, usersA);
// PrefixedUsersArray(users)
// ...
You need to understand how asynchronous code works. A fetch request returns a promise, so you must return the promise and access the value using .then():
function loadLocalJson(path) {
return fetch(path)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok :(');
}
return response.json();
})
.catch(err => console.log('Error', err))
}
function getFilteredAndSortedArray(users, price) {
console.log(users, price);
return users.filter(user => {
return user.salary && user.salary > price;
}).sort(user => user.name);
}
loadLocalJson('users.json').then(users => {
usersB = getFilteredAndSortedArray(users, 1000);
console.log(usersB, users);
})
You do not have to assign users, you can just return the promise, sinc eyou have already called response.json(). Also, your sort function most likely won't work, try something like this:
users.sort((a, b) => a.name.localeCompare(b.name))