nested axios call with await in vue js - javascript

i am new to async and i have an action in vuex that get user's info and i put that in promise and i want to use this method in then block of axios call for login with await because data of user info is important for me
my problem is i cant use await in then block and error says the error says await can only be use in async function
this flow is correct and what is correct way?
store.js:
actions: {
loadUserInfo({commit}){
const headers = {
'Content-Type': 'application/json',
// 'Authorization': localStorage.getItem('access_token'),
'Accept': 'application/json'
}
return new Promise(function(resolve, reject) {
axios.get(process.env.VUE_APP_BASE_URL + process.env.VUE_APP_EDIT_INFO,{headers: headers})
.then(response => {
commit('authenticateUser');
commit('setUserInfo', response.data.result);
resolve();
})
.catch(error => {
console.log(error);
reject();
})
});
}
},
Login.vue:
async login () {
let self = this;
axios.post(process.env.VUE_APP_BASE_URL + process.env.VUE_APP_LOGIN,
this.loginInfo
).
then(function (response) {
await this.$store.dispatch('loadUserInfo').then((res)=>{
this.$emit('authenticateUser', true);
this.$emit('registeredIdentification', self.$store.getters.getUsername)
this.$router.push({ name: 'mainBox' })
});
localStorage.setItem('access_token', response.data.result.access_token)
localStorage.setItem('refresh_token', response.data.result.refresh_token)
})
.catch(function (error) {
// let statusCode = error.response.status;
console.log(error);
});
}

try moving the async declaration so it is "inside" the then:
async login () {
...
.then(async function (response) {
await this.$store.dispatch('loadUserInfo').then((res)=>{
...
}
Using then with async/await may be unnecessary:
async login() {
try {
const loginUrl = process.env.VUE_APP_BASE_URL + process.env.VUE_APP_LOGIN;
const { data } = await axios.post(loginUrl, this.loginInfo)
const { access_token: accessToken, refresh_token: refreshToken } = data.result;
await this.$store.dispatch('loadUserInfo');
this.$emit('authenticateUser', true);
this.$emit('registeredIdentification', this.$store.getters.getUsername)
this.$router.push({ name: 'mainBox' })
localStorage.setItem('access_token', accessToken)
localStorage.setItem('refresh_token', refreshToken)
} catch (error) {
console.log(error);
}
}

Related

Javascript in VueJs: how to return data object from async fetch instead of Promise

I have this action in store
actions: {
testLogin(context, credentials) {
const loginService = new FetchClient();
let d = loginService.post('login', credentials);
console.log(d);
},
and this function in another class imported to store
async post(endpoint, params) {
await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
.then(response => {
return response.json();
})
.then( (data) => {
this.returnData = data.data;
})
.catch(error => {
console.log(error);
});
return this.returnData;
}
And I get PromiseĀ {<pending>} which I can extract data from inside the fetch class but can't access data if I'm in the store because it's a Promise not an object. How can I solve this?
Put the return statement inside the second then block:
async post(endpoint, params) {
await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
.then(response => {
return response.json();
})
.then( (data) => {
this.returnData = data.data;
return this.returnData;
})
.catch(error => {
console.log(error);
});
}
I would even recommend you use the following code for better legibility:
async post(endpoint, params) {
const response = await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
})
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
}
const resp_data = await response.json()
return resp_data.data
}
Then call your method like so:
post(endpoint, params)
.then(data => {// do something with data})
.catch(error => {
error.message; // 'An error has occurred: 404'
});
refer to this async/await guide
Can you try:
async testLogin(context, credentials) {
const loginService = new FetchClient();
let d = await loginService.post('login', credentials);
console.log(d);
}
As #Ayudh mentioned, try the following code:
async post(endpoint, params) {
try{
let response = await fetch(this.url + endpoint, {
'method': 'POST',
headers: this.headers,
body: JSON.stringify(params),
});
let data = await response.json();
this.returnData = data.data;
}catch(e){
console.log(e);
}
return this.returnData;
}

i'm having problems using axios and making requests to a api

const getCustomers = async (token) => {
try {
const response = await axios.get(`${base_url}/customers`, { headers: { 'Authorization': `Bearer ${token}`} })
return response.data
} catch(error) {
logger.error(error)
}
i'm using axios to make a request to an api, and i keep getting the same error.
error: undefined {"config":{"url":"https://api.contaazul.com/v1/customers","method":"get","headers":{"Accept":"application/json","Authorization":"Bearer EU5KBm8ft1ZB4vFy9I89xYQWnzqcbULS","User-Agent":"axios"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1},"code":"HPE_INVALID_HEADER_TOKEN"}
already tried deleting node_modules and using other versions of node
Try this
const getCustomers = async (token) => {
await axios.get(`${base_url}/customers`, {
headers: {
"Authorization": `Bearer ` + token
}
})
.then(response => {
return response.data;
})
.catch(err => {
console.log(err)
});
}

Axios multiple request on interceptor

I'm using the library axios in my react app.
I'm having a problem with the interceptor.
My question is let say I have three requests happening concurrently and I don't have the token, the interceptor calling the getUserRandomToken three time, I want the interceptor will wait until I'm getting the token from the first request and then continue to the others.
P.S. the token he is with an expiration date so I also checking for it and if the expiration date is not valid I need to create a new token.
This is the interceptor:
axios.interceptors.request.use(
config => {
/*I'm getting the token from the local storage
If there is any add it to the header for each request*/
if (tokenExist()) {
config.headers.common["token"] = "...";
return config;
}
/*If there is no token i need to generate it
every time create a random token, this is a axios get request*/
getUserRandomToken()
.then(res => {
/*add the token to the header*/
config.headers.common["token"] = res;
return config;
})
.catch(err => {
console.log(err);
});
},
function(error) {
// Do something with request error
return Promise.reject(error);
}
);
How about singleton object that will handle the token generations? something similar to this:
const tokenGenerator ={
getTokenPromise: null,
token: null,
getToken(){
if (!this.getTokenPromise){
this.getTokenPromise = new Promise(resolve=>{
/*supposed to be a http request*/
if (!this.token){
setTimeout(()=>{
this.token = 'generated';
resolve(this.token);
},0)
}else{
resolve(this.token);
}
})
}
return this.getTokenPromise;
}
you can reference this same object from the interceptors.
see example: JS FIddle
reference: reference
You can return a Promise from interceptor callback to "wait" until promise fullfiles (this will fit your case). Check out this example:
function axiosCall () {
return new Promise((resolve, reject) => {
Axios.post(URL, {apiKey}).then((response) => {
resolve(response.data.message);
}).catch((error) => {
reject(error);
});
});
}
instance.interceptors.request.use((config) => {
return axiosCall().then((tokenResponse) => {
setWebCreds(tokenResponse);
config.headers.Authorization = `Bearer ${tokenResponse}`;
return Promise.resolve(config)
}).catch(error => {
// decide what to do if you can't get your token
})
}, (error) => {
return Promise.reject(error);
});
More details here: https://github.com/axios/axios/issues/754
Following code doing certain tasks:
Update Token on 401
Make a queue of failed requests while the token is refreshing.
Restore the original request after token refreshing.
Once the peculiar request is given 200, remove it from the queue.
Config.js
import axios from 'axios';
import { AsyncStorage } from 'react-native';
import { stateFunctions } from '../../src/sharedcomponent/static';
const APIKit = axios.create({
baseURL: '',
timeout: 10000,
withCredentials: true,
});
const requestArray = [];
// Interceptor for Request
export const setClientToken = token => {
APIKit.interceptors.request.use(
async config => {
console.log('Interceptor calling');
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
config.headers = {
'Authorization': `Bearer ${userToken}`,
'Accept': 'application/json',
"Content-Type": "application/json",
"Cache-Control": "no-cache",
}
// console.log('caling ' , config)
return config;
},
error => {
Promise.reject(error)
});
};
// Interceptor for Response
APIKit.interceptors.response.use(
function (response) {
if (requestArray.length != 0) {
requestArray.forEach(function (x, i) {
if (response.config.url == x.url) {
requestArray.splice(i, 1);
}
});
}
return response;
},
function (error) {
const originalRequest = error.config;
requestArray.push(originalRequest);
let reqData = "username=" + number + "&password=" + pin + "&grant_type=password" + "&AppType=2" + "&FcmToken=null";
// console.log('error ' , error);
if (error.message === "Request failed with status code 401" || error.statuscode === 401) {
if (!originalRequest._retry) {
originalRequest._retry = true;
return axios({
method: 'post',
url: '/api/login',
data: reqData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Cache-Control": "no-cache",
}
})
.then(res => {
let response = res.data;
console.log('successfull Login', response)
if (res.data.StatusCode == 200) {
AsyncStorage.setItem('userToken', JSON.stringify(response.access_token));
stateFunctions.UserId = response.UserId;
stateFunctions.CustomerContactID = response.CustomerContactID;
let obj = {
access_token: response.access_token,
token_type: response.token_type,
expires_in: response.expires_in,
UserId: response.UserId,
CustomerContactID: response.CustomerContactID,
Mobile: response.Mobile,
StatusCode: response.StatusCode
}
AsyncStorage.setItem('logindetail', JSON.stringify(obj));
if (requestArray.length != 0) {
requestArray.forEach(x => {
try {
console.log(x, "request Url");
x.headers.Authorization = `Bearer ${response.access_token}`;
x.headers["Content-Type"] = "application/x-www-form-urlencoded";
APIKit.defaults.headers.common["Authorization"] = `Bearer${response.access_token}`;
APIKit(x)
} catch (e) {
console.log(e)
}
});
}
return APIKit(originalRequest);
}
})
.catch(err => {
console.log(err);
});
}
}
return Promise.reject(error);
}
);
export default APIKit;
Home.js
gettingToken = async () => {
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
await setClientToken(userToken);
}

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);
})
}

Categories

Resources