I have this function in JS:
export let findUser = (user, pass) => fetch(baseURL+'/api/Login',{
method: 'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username:user,
password:pass,
})
})
.then((response) => response.json())
.then((res) => {
if(res.success === true){
return 'A';
}else{
alert(res.message);
}
}).
.done();
But when I call it in React like this :
var user = file.findUser(this.state.username,this.state.password);
I got undefined as content of variable user, How can I pass a value from the first function and get it in react native ?
I would suggest exporting the initial method call and handling the .then() and .done() within the area being exported to. For example:
I have this function in JS:
export let findUser = (user, pass) => fetch(baseURL+'/api/Login',{
method: 'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username:user,
password:pass,
})
})
using in another file
let user // assign user within response block
file.findUser(this.state.username, this.state.password)
.then((res) => { /* do what you want */ })
.then((res) => { /* do what you want */ })
.done()
Related
I need help because I couldn't use a separate function to generate the token - it gives out a promise, not a value. I was told that a value can only be used inside a function.
For each request, I generate a new token in the first request and then pass that token into the second request.
I tried making a separate function to generate the token, but fetch returns a promise.
As a result, I made such a big function and it works.
Is there a way to make a separate function for the first request and pass the result to the second request?
The first token generation function is required frequently, while the second request is always different.
fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
.then(response => response.json())
.then(result => {
fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + result.token,
},
body: JSON.stringify({ 'limit': 10 }),
})
.then(response => response.json())
.then(result => {
this.setState({ data: result.data });
})
})
create a function that return promise
async function getToken() {
return await fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
.then(response => response.json())
.then(result => {
return Promise.resolve(result.token);
}).catch(error => {
return Promise.reject(error);
})
}
async function getReview() {
const token = await getToken().then(token => {
return token
}).catch(error => {
//handle error
});
fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token,
},
body: JSON.stringify({ 'limit': 10 }),
})
.then(response => response.json())
.then(result => {
this.setState({ data: result.data });
})
}
i did not test this code but you get the idea
i will test and update my answer asap
Yes you can with async / await. It will allow you to lift the lexical scope of the API response from inside the .then "callback hell" and into the parent function scope.
Your separate function which fetches the token will return a promise, but then the requesting function will wait for the promise to execute and resolve before continuing.
async function fetchToken() {
const response = await fetch('/api/token', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'id': '5' }),
})
return await response.json();
}
async function getReviews() {
const response = await fetch('/api/reviews', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + result.token,
},
body: JSON.stringify({ 'limit': 10 }),
})
const result = await response.json();
this.setState({ data: result.data });
}
Additionally, if the token call does not need to be made every time the reviews call is made, then you can memoize the value, and use that memoized value.
const tokenMemo = useMemo(async () => await getToken(), []);
async function getReviews() {
const response = await fetch('/api/reviews', {
// ...
'Authorization': 'Bearer ' + tokenMemo,
// ...
}
I have been trying to start using typescript for react native but it has not been easy ride so far, finding it difficult to perform common function like fetch an api once on screen load, below is the current function am using but I dont want to use time outs plus its not even working properly(it has to wait for the actual time I set before it runs and its bad for android), I would like to call the function only once when the page loads, I have also tried using if else statements but I dont know why it not just working on typescript.
(function(){
setTimeout(function () {
const newsUrl = 'http://172.20.10.4:8000/mobile/news';
return fetch(newsUrl, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
}
})
.then((response) => response.json())
.then((data) => {
let newArr = [...data];
setProducts(newArr);
//console.log(data);
alert(38783763);
})
.catch((error) => {
alert(error);
console.error(error);
});
}, 200);
}.call(this));
You can use the useEffect hook and pass an empty array the fetch data once on load.
useEffect(() => {
fetch(newsUrl, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
}
})
.then((response) => response.json())
.then((data) => {
let newArr = [...data];
setProducts(newArr);
})
}, []);
So the issue i have is i want to be able to call a module function, that will then call cy.request() get the response and feed this to another cy.request() in a nice way.
I want to make this code nicer:
Cypress.Commands.add('createUser', (user) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.body.token }),
body: user
})
})
})
I'd like to to have the two cy.requests within their own functions, e.g getAuthToken() and createUser(), so i can wrap that in either a Cypress.Command, or just a module function and call within the test file
const seedUser = (userObject) => {
getAuthToken().then((token) => {
return createUser(token); //where this would return the created user.
}
}
then used like so in the test file
before(()=>{
let user = seedUser();
//or
let user = cy.seedUser();
}
You can use cy.wrap() to wrap the response of your first request and then you can use it anywhere.
Custom commands:
Cypress.Commands.add('getAuthToken', () => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((response) => {
cy.wrap(response).as('getAuthTokenResponse')
})
})
Cypress.Commands.add('createUser', (user) => {
cy.get('#getAuthTokenResponse').then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.token }),
body: user
})
})
})
In your Test file you can just add:
cy.getAuthToken()
cy.createUser(user)
I'm trying to consolidate some code in one of my react components because my componentDidMount method is getting a bit verbose. This gave me the idea to create an api that does all of my data fetching for the entire app.
I'm having an asynchronous issue I'm not sure how to resolve.
I created the separate api file (blurt.js):
exports.getBlurts = function() {
var blurtData = null;
fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((data) => {
blurtData = data;
});
return blurtData;
}
and imported it to my (.jsx) component via
import blurtapi from '../api/blurt.js';
The problem is that when I call blurtapi.getBlurts() within componentDidMount(), the value comes back as null. However, if I write the data to the console like so:
.then((data) => {
console.log(data);
});
all is as it should be. So, the function is returning before the db operation completes, hence the null value. How would I reign in the asynchronous aspect in this case? I tried an async.series([]) and didn't get anywhere.
Thanks
So fetch returns a promise, which it is async , so any async code will run after sync code. so this is the reason you get null at first.
However by returning the async function , you are returning a promise.
Hence this code:
exports.getBlurts = async () => {
const data = await fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
const jsonData = await data.json();
return jsonData;
}
To retrieve any promise data, you need the then function,
so in your componentDidMount, you will do:
componentDidMoint() {
blurtapi.getBlurts()
.then(data => console.log(data)) // data from promise
}
Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
async/await:
https://javascript.info/async-await
I hope this makes sense.
fetch call returns a promise. therefore in your function u do something like this
exports.getBlurts = function() {
var blurtData = null;
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
}
And do this in your componentDidMount
componentDidMount(){
blurtapi.getBlurts().then((data)=>{
this.setState({data})
}
}
In your example return blurtData; line will run synchronously, before the promise is resolved.
Modify getBlurts as:
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((data) => {
return data;
});
}
And in componentDidMount:
componentDidMount() {
getBlurts.then((data) => {
// data should have value here
});
}
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(res => return res)
async componentDidMount() {
const response = await blurtapi.getBlurts();
}
or
exports.getBlurts = function() {
return fetch('/getblurts/false', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
componentDidMount() {
const data = blurtapi.getBlurts()
.then(data => {
// Do something or return it
return data;
});
}
I'm trying to check the status of a login via REST call and JWT token so that if that status is not ok then it'll return false, but this is what I'm getting.
export function login(data){
fetch('http://localhost:8000/token-auth/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(res => res.json())
.then(json =>
console.log(json.token) <= This prints correctly
)
}
I tried adding in a check in this function, but then I no longer get the the token printed out
export function login(data){
fetch('http://localhost:8000/token-auth/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(res => {
if(res.ok){
console.log(res.json()) <= This prints something about promise
console.log(res.json().token) <= this prints 'undefined'
}
}).then(json =>
console.log(json.token) <= This prints 'undefined'
)
}
Can you use a catch block instead? Like so:
export function login(data){
fetch('http://localhost:8000/token-auth/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(res => res.json())
.then(json =>
console.log(json.token)
).catch(error =>
console.log(error.response)
)
}