Not working on cancellation of POST in Axios - javascript

The code is not working after the cancellation of POST in Axios. Can you tell me, what is wrong?
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios
.post(
"http://api.image-service/upload",
data,
{
headers: { "Content-Type": "multipart/form-data" }
},
{
cancelToken: source.token
}
)
.then(response => {
if (response.data.StatusCode == 1) {
console.log("Retry", response.data);
} else if (response.data.StatusCode == 0) {
console.log("Success", response.data);
}
})
.catch(error => {
if (axios.isCancel(error)) {
console.log("Post Request canceled");
} else {
console.log("Error connecting to server", error);
}
});
source.cancel();
And one more question: can I do cancellation from other function? For example: if I wait more then 1 minute, I want to click the button for cancel request.

I faced the same issue with a get request.
You need to pass headers in axios properties.
axios.get(url, { cancelToken: ..., headers: { ... } }).then...

Related

Axios request returns 401 despite having an authorization header

I'm trying to patch data to a django API using axios using this snippet:
nextQuestion = () => {
if (this.state.currentIndex === 0) return;
const token = this.props.token;
const configs = {
headers: {
Authorization: `Token ${token}`,
},
data: {
quiztaker: this.state.data[0].quiz.quiztakers_set.id,
question: this.state.data[0].quiz.question_set[this.state.currentIndex]
.id,
answer: Number(this.state.answer),
},
};
console.log(configs);
axios
.patch("/api/save-answer/", configs)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
this.setState({
currentIndex: this.state.currentIndex - 1
});
};
I have confirmed that the token does indeed exist and that it is authorised to access and make changes to that endpoint through insomnia. Did i do anything wrong with how i set up axios? or is there something else i'm not getting? Apologies if it's an obvious mistake, still quite new to react.
With axios.patch() it should be executed axios.patch(url, data, config)....
const data = {
"quiztaker": this.state.data[0].quiz.quiztakers_set.id,
"question": this.state.data[0].quiz.question_set[this.state.currentIndex].id,
"answer": Number(this.state.answer),
};
const token = this.props.token;
const configs = {
"headers": {
"Authorization": `Token ${token}`,
},
};
axios
.patch("/api/save-answer/", data, configs)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});

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

How to properly pass server error response in react?

is a bit of a situation
after simple login
i'v tried to properly handle the server error response but at first i thought it will be simple. i was wrong.
the press login function rely on the login function to pass the login status to check if the user is or not logged.
in a way the code works but it will be great if can get the server response and display.
i've tried to use catch or get a response from the login function. either way still not getting the responde. please someone could spare a hint related to this of problem?
login handler on login.jsx
pressLogin() {
return auth
.login(this.state.email, this.state.password)
.then(response => {
this.props.updateAuth();
let res = response.text();
if (response.login_status == false) {
let errors = res;
throw response.json();
//this.setState({ error: errors });
} else {
// console.log('asdasd')
// this.forceUpdate();
this.setState({ redirectToHome: true });
}
})
.catch(errors => {
return errors;
console.log("Error");
});
}
}
if i set a state in catch just setting a string works but it will be great if can get the server side errors
the login on auth.js
login(email, password) {
return fetch("/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
email: email,
password: password
})
})
.then(resp => {
if (resp.status >= 200 && resp.status < 300) {
return resp.text();
} else {
throw resp.json();
}
})
.then(response => {
if (!response.status) {
window.localStorage.setItem("auth_token", response);
return {
login_status: true
};
} else {
return {
login_status: false
};
}
})
.catch(error => {
console.log("Error" + error);
return {
login_status: false
};
});
},

Api call using fetch with method get

I have to set an header in api call. My POST API calls are working fine. But in my get api calls, header is not getting set.
return fetch('http://api-call.com', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'custom-security':'XXXX',
'Purchase-Code':'XXXXXXX',
'Content-Type':'application/json',
'Cache-Control':'max-age=640000'
}
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.catch((error) => {
console.error(error);
});
You should setup a Request object and pass your headers wrapped into a Headers object, like:
var request = new Request('http://api-call.com', {
method: 'GET',
headers: new Headers({
'Accept': 'application/json',
'custom-security':'XXXX',
'Purchase-Code':'XXXXXXX',
'Content-Type':'application/json',
'Cache-Control':'max-age=640000'
})
});
Then just invoke fetch with your request as parameter:
fetch(request)
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
})
.catch((error) => {
console.error(error);
});
Check reference
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosGetCall()
Authenticated POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
},{
headers: {
Authorization:
`Bearer ${token}`
}
})
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosPostCall()

Async and localStorage not working properly

So I'm using React with React-Router.
I have a onEnter hook which checks if the user is authenticates yes/no and executes the desired action.
export function requireAuth(nextState, replaceState) {
if (!isAuthenticated()) {
if (!Storage.get('token')) replaceState(null, '/login');
return delegate().then(() => replaceState(null, nextState.location.pathname));
}
if (nextState.location.pathname !== nextState.location.pathname) {
return replaceState(null, nextState.location.pathname);
}
}
When the token is expired I call a delegate function which looks like:
export function delegate() {
const refreshToken = Storage.getJSON('token', 'refresh_token');
return getData(endpoint)
.then(res => {
Storage.set('token', JSON.stringify({
access_token: res.data.access_token,
refresh_token: refreshToken,
}));
});
}
The delegate function indeed refresh the tokens in the localStorage. But the requests after the replaceState are not using the updated token, but the previous one. I think this is a async issue, someone knows more about this?
Edit: The function where I use the token:
function callApi(method, endpoint, data) {
return new Promise((resolve, reject) => {
let headers = {
'Accept': 'application/json',
'X-API-Token': Storage.getJSON('token', 'access_token'),
};
const body = stringifyIfNeeded(data);
const options = { method, headers, body };
return fetch(endpoint, options)
.then(response =>
response.json().then(json => ({ json, response }))
).then(({ json, response }) => {
if (!response.ok) {
reject({ json, response });
}
resolve(json);
}).catch((error, response) => {
reject({ error, response });
});
});
}

Categories

Resources