I am trying to create a function, that sends a request to my API with fetch & waits for the result - if it returns data, I want the function to return true, otherwise false.
const loggedIn = async () => {
const response = await fetch(ENDPOINT_URL, {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: query,
})
})
const json = await response.json()
// data gets logged
console.log(json.data)
if(json.data) {
return true
} else {
return false
}
}
If I call loggedIn(), I still receive Promise {<pending>}?
An async function returns a promise. From a caller's perspective, it's no different from any other function returning a promise. When you call it, you get a promise which you need to handle, not the value, because that would require blocking.
It sounds like you expected it to block your code. To get that, call it from another async function:
(async () => {
try {
console.log(await loggedIn()); // true or false
} catch (e) {
console.log(e);
}
})();
Related
I think I am probably missing something pretty simple.
in src/api/index.js I have the following:
export async function loginUser(username, password) {
try {
const response = await fetch(`${BASE}/users/login`, {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: {
username: username,
password: password
}
})
})
.then(response => response.json())
.then(result => {console.log(result)
const key = result.data.token
localStorage.setItem('stToken', JSON.stringify(key))
localStorage.setItem('username', JSON.stringify(username))
})
return response
} catch (error) {
console.log(error);
}
}
My loginUser is being called in my onSubmit handler in my src/component/login.js
const submitHandler = async (event) => {
event.preventDefault()
setUserData( {username, password})
const response = await loginUser(username, password)
alert({response})
console.log(response.data)
}
This API call returns from the loginUser function, when called by onSubmit:
{success: true, error: null, data: {…}}
data: {token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2M…TU2fQ.4l7g5y8hlEDxlmkWUPiVIfM6XWCqHa0410QXGLy72vw', message: 'Thanks for logging in to our service.'}
error: null
success: true
[[Prototype]]: Object
However, whatever I try to access the return data from the submitHandler (such as console.log or any variation of response.data.token I try, I just get null. As of right now the only way for me to access any API returns in my API folder are via local storage.
Please help me identify what i am missing.
First of all, you are using both promises (.then) and async await.
When you await the fetch.then.then you actually awaits for the last returned value. In your case, since you return nothing (undefined) from your last .then, you can't access the data.
Try return the result -
const response = await fetch(`${BASE}/users/login`, {...})
.then(response => response.json())
.then(result => {console.log(result)
const key = result.data.token
localStorage.setItem('stToken', JSON.stringify(key))
localStorage.setItem('username', JSON.stringify(username))
return result; // this is the line I added
})
I am having a Lambda function, in which I am taking a parameter from Query String and using it to call a downstream service that will inturn return a promise. I am unable to send back the response received by the Promise.
This is my Lambda function:
export const handler = async (event) => {
let sessionId = event.queryStringParameters.sessionId;
const testClient = new Client.WebStoreClient(config);
const sessionResponse = getSession(testClient, sessionId);
sessionResponse.then(function (result) {
console.log(result);
});
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
};
async function getSession(testClient, sessionId) {
let data = await testClient.getSession(sessionId, headers)
.then((response) => response.body);
return data;
}
When I am executing this, I am getting a null response: { statusCode: 200, body: '{}' } from the Lambda function output. I tried to console log the value that I have gotten and was receiving this: Promise { <pending> }
I am suspecting this to be a Javascript/Typescript Promise issue which I am slightly neglecting. Any help is appreciated here. Thanks in advance.
In your response, you are trying to stringify the promise instead of the promise value and it gives you an empty object as a String.
You can try it:
JSON.stringify(Promise.resolve(1)) // output is "{}"
You can only access the value of a Promise from inside the callback you pass to then.
Think of it this way: inside of then is the future, the surrounding code is the present. You can't reference future data in the present.
You probably wanted to write
return sessionResponse.then(function (result) {
return {
statusCode: 200,
body: JSON.stringify(result),
}
});
The above returns a promise containing your response.
You could have also just written getSession this way
function getSession(testClient, sessionId) {
return testClient.getSession(sessionId, headers)
.then((response) => response.body);
}
I suggest that you practice using promises without async/await
An alternative to geoffrey's answer, note that both of your functions are async, meaning you can use the same await keyword you used in getSession().
export const handler = async (event) => {
// ...
const sessionResponse = await getSession(testClient, sessionId);
// ^
console.log(sessionResponse);
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
};
async function getSession(testClient, sessionId) {
let data = await testClient.getSession(sessionId, headers)
.then((response) => response.body);
return data;
}
This is roughly the equivalent of...
export const handler = (event) => {
// ...
return getSession(testClient, sessionId).then((data) => {
console.log(data);
const response = {
statusCode: 200,
body: JSON.stringify(sessionResponse),
};
return response;
});
};
function getSession(testClient, sessionId) {
return testClient
.getSession(sessionId, headers)
.then((response) => response.body);
}
Note that your getSession() function is returning a Promise by virtue of async (and in the translated example above). Your handler() function is likewise returning a Promise, so whatever is calling it will need to use a .then() or be async itself to leverage an await. As you can see this asynchronous requirement cascades.
I'm making a POST request that takes ~10 seconds to finish... but my alert displays immediately on click, before the server returns 200. Why? And how do I fix it to wait until the server completes operation?
const handleClick = async () => {
const response = await fetch("/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(highlights),
}).then(alert("hi!"));
};
If I change my .then to
.then(() => {alert("hi!");}) as was suggested below, the page flashes/seems to refresh when the server request is made but the alert doesn't show at all
Update:
If I use this code:
const handleClick = async () => {
try {
const response = await fetch("/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(highlights),
});
alert("first");
} catch (error) {}
alert("second");
};
The second alert fires right when the button is pressed, the first alert never fires.
Async/await is introduced to overcome the then/catch chaining issue. You dont need to use then , you have to use try/catch. async/await always used with try/catch only.
const handleClick = async () => {
try{
const response = await fetch("/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(highlights),
})
alert("hi!")
}
catch(error){}
}
When you use try/ catch , control will not go further until i/o call is finished. So you can put alert or any code out of try catch block also. It will be executed once await call is completed.
Like this
try{
const response = await fetch("/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(highlights),
})
}
catch(error){}
}
alert("hi!")
Try this.
If you are using reactjs and nodejs, then I have simulated your requirement and it is working as expected.
I have used reactjs hooks.
Alert gets trigger once post call is succeeded.
You can check this out.
https://github.com/ajaysikdar/reactjs-nodejs-alert
Try:
.then(() => { alert("hi"); });
The then function expects you to pass it a function, but you are actually calling a function (alert), and passing the return value of that function to then.
I am using react-native, mongo DB and node js and I need to create some database functions and put them in some modules to be able to reuse them whenever I want. To fetch data from the mongo database, I use the fetch() function which returns a promise. So, for all functions that I created that did not return a value, I used .then and I faced no problems. On the other side, when I return a value inside a fetch().then() function and use this returned value, I get undefined. The code I use for the function looks like:
export const getUsers = () => {
//I cannot use this function because of returning a promise
fetch("http://1jjsd12zaws.ngrok.io/database/", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
res.json();
})
.then((data) => {
return JSON.stringify(data);
});
};
Then, when I try to run this code:
let users=getUsers();
console.log(users);
It prints undefined.
What I think is going on is that the console.log(users) runs before getUsers() returns its value. But I do not know why does this happen and I want it to wait for getUsers() to execute then, completes its work.
You need to return fetch(..) inside getUsers (that's why you are getting undefined)
You also need to return res.json() inside the first then
Since getUsers returns a Promise, then you need to use .then (or async/await) to access the promise value: getUsers().then(users => {...})
const getUsers = () => {
return fetch('http://1jjsd12zaws.ngrok.io/database/', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
return res.json();
})
.then(data => {
return JSON.stringify(data);
});
};
getUsers().then(users => console.log(users))
Async and await should cover it. The example on MDN docs explains it better than I can and should apply to your use case.
I have a function like so:
check_auth(){
fetch(Urls.check_auth(), {
credentials: 'include',
method: 'GET'
}).then(response => {
if(response.ok) return response.json();
}).then(json => {
return json.user_logged_in;
});
}
And then I try to do this:
if(this.check_auth()){
// do stuff
} else {
// do other stuff
}
But, this.check_auth() is always undefined.
What am I missing here? I thought that within fetch's then() was where the resolved Promise object was therefore I thought that I'd get true when the user was logged in. But this is not the case.
Any help would be greatly appreciated.
Use callback
check_auth(callback){
fetch(Urls.check_auth(), {
credentials: 'include',
method: 'GET'
}).then(response => {
if(response.ok) return response.json();
}).then(json => {
callback(json.user_logged_in);
});
}
check_auth(function(data) {
//processing the data
console.log(d);
});
In React it should be easier to handle, You can call a fetch and update the state, since on every update of state using setState the render method is called you can use the state to render
check_auth = () =>{
fetch(Urls.check_auth(), {
credentials: 'include',
method: 'GET'
}).then(response => {
if(response.ok) return response.json();
}).then(json => {
this.setState({Result: json.user_logged_in});
});
}
it can be solved with the es6 aync functions
Note: the example is different from what OP asked but it gives some hints on how it should be done
const loadPosts = async () => {
const response = await fetch(/* your fetch request */);
const posts = await response.json();
return posts;
};
Async calls doesn't always resolve to be used anywhere within your app when you use .then(). The call is still async and you need to call your if-statement when you are calling your fetch. So anything that relies on the data you are fetching has to be chained to the fetch with .then().
check_auth(){
fetch(Urls.check_auth(), {
credentials: 'include',
method: 'GET'
}).then(response => {
if(response.ok) return response.json();
}).then(json => {
return json.user_logged_in;
}).then(user => checkIfAuthSuccess(user)); //You have to chain it
}
Wrapping your if-statement in a function or however your code looks like.
checkIfAuthSuccess(user){
if(user){
// do stuff
} else {
// do other stuff
}
}
Nice video about async behavior in JavaScript: Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014
To return data as JSON from Promise you should call it with await modifier from async function.
For example:
const checkAuth = async () => {
const data = await fetch(Urls.check_auth())
.then(response => response.json())
.then(json => json.user_logged_in)
return data;
}
More info about promises you can find here