How to get value of async function and save it - javascript

I'm new in javascript. I've a async function getListBar. Inside getListBar i use return result of getAccount like a input of function fetch( you can see user.access_token) . Code run correct but i don't want call getAccount everytime i use getListBar. So how can i get result of getAccount and save it ?
I've tried many ways but promise very difficult to me , i don't know how to save result of it
async function getAccount() {
try {
let response = await fetch(apiAuthen,
{
method: 'POST',
headers: {
Accept: '*/*',
'Authorization': 'Basic a2VwbGxheTpva2Vwba2VwbGxaQ1YWwjJA==',
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'password',
},
body: qs.stringify({
'grant_type': 'password',
'username': 'abc',
'password': 'abc',
'client_id': 'abc',
})
})
let responseJson = await response.json();
return responseJson.data;
} catch (error) {
console.log(`Error is : ${error}`);
}
}
async function getListBar() {
try {
const user = await getAccount().then(user => { return user });
let response = await fetch(apiBar,
{
headers: {
'Authorization': 'Bearer ' + user.access_token
}
})
let responseJson = await response.json();
return responseJson.data;
} catch (error) {
console.log(`Error is : ${error}`);
}
}
getAccount will return a Promise like this and i want save access_token in it
Promise {_40: 0, _65: 0, _55: null, _72: null}
_40: 0
_55: {access_token: "41b369f2-c0d4-4190-8f3c-171dfb124844", token_type: "bearer", refresh_token: "55867bba-d728-40fd-bdb9-e8dcd971cb99", expires_in: 7673, scope: "read write"}
_65: 1
_72: null
__proto__: Object

If it is not possible to simply store a value in the same scope that these functions are defined, I would create a Service to handle getting the user. Preferably in its own file
AccountService.js
class AccountService {
getAccount = async () => {
if (this.user) {
// if user has been stored in the past lets just return it right away
return this.user;
}
try {
const response = await fetch(apiAuthen, {
method: 'POST',
headers: {
Accept: '*/*',
Authorization: 'Basic a2VwbGxheTpva2Vwba2VwbGxaQ1YWwjJA==',
'Content-Type': 'application/x-www-form-urlencoded',
grant_type: 'password'
},
body: qs.stringify({
grant_type: 'password',
username: 'abc',
password: 'abc',
client_id: 'abc'
})
});
const responseJson = await response.json();
this.user = responseJson.data; // store the user
return this.user;
} catch (error) {
console.log(`Error is : ${error}`);
}
// you should decide how to handle failures
// return undefined;
// throw Error('error getting user :(')
};
}
// create a single instance of the class
export default new AccountService();
and import it where needed
import AccountService from './AccountService.js'
async function getListBar() {
try {
// use AccountService instead
const user = await AccountService.getAccount().then(user => { return user });
let response = await fetch(apiBar,
{
headers: {
'Authorization': 'Bearer ' + user.access_token
}
})
let responseJson = await response.json();
return responseJson.data;
} catch (error) {
console.log(`Error is : ${error}`);
}
}
You will still be calling getAccount each time in getListBar but it will only fetch when AccountService has no user stored.

Now i write in the different way
export default class App extends Component {
constructor() {
super();
this.state = {
accessToken: '',
users: [],
listBar: []
}
}
//Get Account
Check = () => {
getAccount().then((users) => {
this.setState({
users: users,
accessToken: users.access_token
});
}).catch((error) => {
this.setState({ albumsFromServer: [] });
});
}
//Get Account
getAccount() {
return fetch(apiAuthen,
{
method: 'POST',
headers: {
Accept: '*/*',
'Authorization': 'Basic a2VwbGxheTpva2Vwba2VwbGxaQ1YWwjJA===',
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'password',
},
body: qs.stringify({
'grant_type': 'password',
'username': 'abc',
'password': 'abc',
'client_id': 'abc',
})
}).then((response) => response.json())
.then((responseJson) => {
this.setState({
users: responseJson.data,
accessToken: responseJson.data.access_token
});
return responseJson.data
})
.catch((error) => {
console.error(error);
});
}
//Get List Bar
getListBarFromServer() {
return fetch(apiBar, {
headers: {
'Authorization': 'Bearer ' + this.state.accessToken
}
}).then((response) => response.json())
.then((responseJson) => {
console.log(this.getListBarFromServer()) <---- Just run if console
this.setState({ listBar: responseJson.data });
return responseJson.data
})
.catch((error) => {
console.error(error);
});
}
componentDidMount() {
this.getAccount();
this.getListBarFromServer();
}
render() {
return (
<View style={{ top: 100 }}>
<FlatList data={this.state.listBar} renderItem={({ item }) => {
return (
<View>
<Text>{item.bar_id}</Text>
</View>
)
}}>
</FlatList>
</View>
)
}
}
It's just run when i console.log(this.getListBarFromServer()) .Please explain to me why?

Related

Issues with returning values from nested axios call in ReactJs

The below function does not return any value when the lenght of the output from the first call. I have given comment in the line of code that is creating issues in the below snippet. Can you please advise what is the issue with my code?
async createProfileByUserIDNew(data,email) {
const AuthStr = 'Bearer ' + getToken();
const response = await axios
.get(`${baseUrl}/profiles?email=${email}`, {
headers: { Authorization: AuthStr },
})
.then((response) => {
if (response.data.length===0){
return axios
.post(`${baseUrl}/buyer-profiles`, data, {
headers: { Authorization: AuthStr },
})
}else{
console.log(response.data); // Printing the proper results
return response.data, // not returning any results to next then.Return statement not working
}
}
}).then((response) => {
return{
items: response.data, // returning proper results for if statement but failing for else condition
}
})
.catch((error) => (console.log( JSON.stringify(error)) ));
}
///calling the nested axios call
const ret = MyProfileRepository.createProfileByUserIDNew(
data,
user.email
);
ret.then(function (response) {
console.log(response); //Printing 'undefined'
This.setState({ buyerProfileId: response.items.id });
});
Your createProfileByUserIDNew is an async function, meaning you need a return statement:
async function createProfileByUserIDNew() {
const AuthStr = 'Bearer ' + getToken();
const response = await axios.get(...).etc;
return response;
}
Alternatively, you can also directly return a promise:
async function createProfileByUserIDNew() {
const AuthStr = 'Bearer ' + getToken();
return axios.get(...).etc;
}
You should have only one .then callback function. Here is the correct implementation
async createProfileByUserIDNew(data,email) {
const AuthStr = 'Bearer ' + getToken();
const response = await axios
.get(`${baseUrl}/profiles?email=${email}`, {
headers: { Authorization: AuthStr },
})
.then((response) => {
if (response.data.length===0){
return axios
.post(`${baseUrl}/buyer-profiles`, data, {
headers: { Authorization: AuthStr },
}).then((response) => {
return{
items: response.data, // returning proper results.working as expected
}
})
.catch((error) => (console.log( JSON.stringify(error)) ));
}
}else{
console.log(response.data[0]); // Printing the proper results
return{
items: response.data[0], // not returning any results.Return statement not working
}
}
})
But you can improve your conditions but for the sake of argument, this code will work.
The problem is that when you return from your first then function, the promise falls through to the second then function. The else condition of your first function returns an object shaped as { items: data } while the second then function is expecting a response object, not an object w/ an items key.
You could handle this in a few ways:
You're defining an async function, but you're not doing anything asynchronously (in terms of ES6 syntax). You could convert your whole function to this syntax to async/await properly within your conditional statements.
You could convert your first then to an async function, then asynchronously fetch the second request from there.
You could change the structure of what you return in the else condition so that it looks like a response object, and can be parsed properly in the secondary then function.
In addition, you are not returning the response promise.
Solution 1
async createProfileByUserIDNew(data, email) {
const AuthStr = 'Bearer ' + getToken();
try {
let response = axios.get(`${baseUrl}/profiles?email=${email}`, {
headers: { Authorization: AuthStr },
});
if (response.data.length === 0) {
response = await axios.post(`${baseUrl}/buyer-profiles`, data, {
headers: { Authorization: AuthStr },
});
}
return {
items: response.data[0],
};
} catch (error) {
console.log(JSON.stringify(error));
}
}
Solution 2
createProfileByUserIDNew(data,email) {
const AuthStr = 'Bearer ' + getToken();
return axios
.get(`${baseUrl}/profiles?email=${email}`, {
headers: { Authorization: AuthStr },
})
.then(async (response) => {
if (response.data.length === 0) {
response = await axios
.post(`${baseUrl}/buyer-profiles`, data, {
headers: { Authorization: AuthStr },
});
}
return {
items: response.data[0],
};
})
.catch((error) => {
console.log(JSON.stringify(error));
});
}
Solution 3
createProfileByUserIDNew(data,email) {
const AuthStr = 'Bearer ' + getToken();
return axios
.get(`${baseUrl}/profiles?email=${email}`, {
headers: { Authorization: AuthStr },
})
.then((response) => {
if (response.data.length === 0) {
return axios
.post(`${baseUrl}/buyer-profiles`, data, {
headers: { Authorization: AuthStr },
});
} else {
return {
response: {
data: {
items: response.data[0],
},
},
};
}
}).then((response) => {
return {
items: response.data,
};
})
.catch((error) => {
console.log(JSON.stringify(error));
});
}

the code is doing its work but I'm not getting the desired output

whenever I click the delete button its works fine but I don't get the output like " deleted successfully " its shows .then undefined..
const deleteThisCategory = (CategoryId) => {
deleteCategory(CategoryId, user._id, token).then(data => {
if (data.error) {
console.log(data.error);
} else {
preload();
}
});
};
here is the delete category API call
export const deleteCategory = (userId, categoryId , token) => {
fetch(`${API}/category/${categoryId}/${userId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type":"application/json"
},
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
It should be like this. deleteCategory needs to send only promise. Later where ever you are resolving you have to use then.
export const deleteCategory = (userId, categoryId , token) => {
return fetch(`${API}/category/${categoryId}/${userId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type":"application/json"
}
})
};
const deleteThisCategory = (CategoryId) => {
deleteCategory(CategoryId, user._id, token).then(data => {
preload();
}).catch(err => {
console.log(err);
})
};

Async/Await in fetch() how to handle errors

I have stripe async code in my React app, and trying to add error handling in my code but have no idea how to handle it. i know how to do it with .then() but async/await is new to me
EDITED
added .catch() i got errors in network tab in response tab.
but i can log it to console?
submit = async () => {
const { email, price, name, phone, city, street, country } = this.state;
let { token } = await this.props.stripe
.createToken({
name,
address_city: city,
address_line1: street,
address_country: country
})
.catch(err => {
console.log(err.response.data);
});
const data = {
token: token.id,
email,
price,
name,
phone,
city,
street,
country
};
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).catch(err => {
console.log(err.response.data);
});
console.log(response);
if (response.ok)
this.setState({
complete: true
});
};
thanks
Fetch detects only network errors. Other errors (401, 400, 500) should be manually caught and rejected.
await fetch("/charge/pay", headers).then((response) => {
if (response.status >= 400 && response.status < 600) {
throw new Error("Bad response from server");
}
return response;
}).then((returnedResponse) => {
// Your response to manipulate
this.setState({
complete: true
});
}).catch((error) => {
// Your error is here!
console.log(error)
});
If you are not comfortable with this limitation of fetch, try using axios.
var handleError = function (err) {
console.warn(err);
return new Response(JSON.stringify({
code: 400,
message: 'Stupid network Error'
}));
};
var getPost = async function () {
// Get the post data
var post = await (fetch('https://jsonplaceholder.typicode.com/posts/5').catch(handleError));
// Get the author
var response = await (fetch('https://jsonplaceholder.typicode.com/users/' + post.userId).catch(handleError));
if (response.ok) {
return response.json();
} else {
return Promise.reject(response);
}
};
You can either use try/catch just like normal, imperative programming:
try {
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
} catch(error) {
// Error handling here!
}
Or you can mix-and-match .catch() just like you do with promises:
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).catch(function(error) {
// Error handling here!
});
Wrap your await with try catch.
try {
let response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
console.log(response);
} catch (error) {
console.log(error);
}
This works if server returns { message: "some error" } but I'm trying to get it to support res.statusText too:
const path = '/api/1/users/me';
const opts = {};
const headers = {};
const body = JSON.stringify({});
const token = localStorage.getItem('token');
if (token) {
headers.Authorization = `Bearer ${token}`;
}
try {
const res = await fetch(path, {
method: opts.method || 'GET',
body,
headers
});
if (res.ok) {
return await (opts.raw ? res.text() : res.json());
}
const err = await res.json();
throw new Error(err.message || err.statusText);
} catch (err) {
throw new Error(err);
}
async function loginWithRedirect(payload: {
username: string;
password: string;
}) {
const resp = await (await fetch(`${env.API_URL}/api/auth/login`, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(payload),
credentials: "include",
})).json();
if (resp.error) {
dispatch({type: "ERROR", payload: resp.error.message});
} else {
dispatch({type: "LOGIN", payload: resp});
}
}
If response.ok is false you can throw an error then chain catch method after calling your function as follows
async function fetchData(){
const response = await fetch("/charge/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
if(!response.ok){
const message = `An error occured: ${response.status}`;
throw new Error(message);
}
const data = await response.json();
return data;
}
fetchData()
.catch(err => console.log(err.message));
I write promise function for using fetch in async await.
const promisyFetch = (url, options) =>
new Promise((resolve, reject) => {
fetch(url, options)
.then((response) => response.text())
.then((result) => resolve(result))
.catch((error) => reject(error));
});
By the way i can use it easly in async with try catch
const foo = async()=>{
try {
const result = await promisyFetch('url' requestOptions)
console.log(result)
} catch (error) {
console.log(error)
}
}
It was simple example, you could customize promisyFetch function and request options as you wish.
const data = {
token: token.id,
email,
price,
name,
phone,
city,
street,
country
};
axios
.post("/charge/pay", data)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err.response.data);
});

How use await keyword along with asyncstorage setitem for server response?

I'm trying to use asyncstorage in my react native app.The problem is the server response I'm getting takes some delay so I want to wait for the response then I want to use that responseData.user_id to be saved in my app.I'm using nodejs as backend and mysql db.So after user registration I'm inserting it to db at the same time I've written another query for fetching their user_id (PK).So this responseData is getting to client and I'm trying to take that user_id from the response.So I've written something like this
onPressRegister = async () => {
try {
let response = await fetch('http://192.168.1.2:3000/users/registration', {
method: 'POST',
headers: {
'Accept': 'applictaion/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact: this.state.contact,
password: this.state.password,
})
});
let responseData = await response.json();
if (responseData) {
try {
Action.firstScreen();
await AsyncStorage.setItem('userid', JSON.stringify(responseData.userData.phone_no));
}
catch (e) {
console.log('caught error', e);
}
}
} catch (error) {
console.error(error)
}
}
And in my next screen I'm accessing the userid like this.And passing it the next API call like this.
getUserId = async () => {
let userId = await AsyncStorage.getItem('userid');
return userId;
}
onPressYes = (workType) => {
this.getUserId().then((userId) => {
this.setState({userId:userId})
})
fetch('http://192.168.1.2:3000/users/user_request',{
method:'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
workType,
phone:this.state.userId
})
})
.then(response => response.json())
.then((responseData) => {
this.setState({
data:responseData
});
});
}
But this is the error I'm getting.
Try this:
onPressRegister = async () => {
try {
let response = await fetch('http://192.168.1.6:3000/users/registration', {
method: 'POST',
headers: {
'Accept': 'applictaion/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact: this.state.contact,
password: this.state.password,
})
});
let responseData = await response.json();
if (responseData) {
try {
await AsyncStorage.setItem('userid', JSON.stringify(responseData.user_id));
}
catch (e) {
console.log('caught error', e);
}
}
} catch (error) {
console.error(error)
}
}
To access the value in some other component:
getUserId = async () => {
let userId = await AsyncStorage.getItem('userid');
return userId;
}
componentWillMount() {
this.getUserId().then((userId) => {
console.log(userId);
})
}

Issue with POST Request being passed as GET

I'm going to insert the whole module in case you need to see other aspects of the code. The call in question is the addTracks method. The project is to allow the person to search the spotify library, create a playlist of songs, then add the playlist to their account. Everything works fine, besides the tracks actually saving to the account, I get a 401 error on the API, but both Chrome and FireFox also label it as a GET call, instead of as a POST. The error is an authentication error, but I should be authorized correctly, the only odd thing for authorization is the scope, which is taken care of in the redirect in getAccessToken(). What am I missing here? In case you need it: Spotify add track documentation
let accessToken;
let expiresIn;
const clientId = '86f8f621d81a4ce18bd21da9fd2da2b1';
const redirectURI = 'http://localhost:3000/';
const Spotify = {
getAccessToken() {
if (accessToken) {
return accessToken;
} else if (window.location.href.match(/access_token=([^&]*)/) != null) {
accessToken = window.location.href.match(/access_token=([^&]*)/)[1];
expiresIn = window.location.href.match(/expires_in=([^&]*)/)[1];
window.setTimeout(() => accessToken = '', expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
} else {
window.location = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectURI}`;
}
},
async search(term) {
if (accessToken === undefined) {
this.getAccessToken();
}
try {
let response = await fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`
}
});
if (response.ok) {
let jsonResponse = await response.json();
let tracks = jsonResponse.tracks.items.map(track => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
uri: track.uri
}));
return tracks;
}
} catch (error) {
console.log(error);
}
},
async savePlaylist(name, trackURIs) {
if (accessToken === undefined) {
this.getAccessToken();
}
if (name === undefined || trackURIs === undefined) {
return;
} else {
let userId = await this.findUserId();
let playlistID;
fetch(`https://api.spotify.com/v1/users/${userId}/playlists`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": 'application/json'
},
body: JSON.stringify({
name: name
})
}).then(response => {
return response.json()
}).then(playlist => {
playlistID = playlist.id;
this.addTracks(playlistID, trackURIs, userId);
});
}
},
addTracks(playlistID, trackURIs, userId) {
console.log(trackURIs);
fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistID}/tracks`), {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": 'application/json'
},
body: JSON.stringify({
uris: trackURIs
})
}
},
findUserId() {
if (accessToken === undefined) {
this.getAccessToken();
}
let userId;
return fetch(`https://api.spotify.com/v1/me`, {
headers: {
Authorization: `Bearer ${accessToken}`
}
}).then(response => {
return response.json()
}).then(jsonResponse => {
userId = jsonResponse.id;
return userId;
});
}
};
export default Spotify;
I'm beginner but probably you should check bracket in fetch() method in addTracks()
addTracks(playlistID, trackURIs, userId) {
console.log(trackURIs);
fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistID}/tracks`->)<-, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": 'application/json'
},
body: JSON.stringify({
uris: trackURIs
})
}
},
correct
addTracks(playlistID, trackURIs, userId) {
console.log(trackURIs);
fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistID}/tracks`, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": 'application/json'
},
body: JSON.stringify({
uris: trackURIs
})
})
},

Categories

Resources