i'm getting isssue while calling API in Useeffect in reactJs - node.js

I'm calling two methods in useeffect but when api1 get called it get executed till await axios.put and then api2 get called without getting the response from api1. And after getting a reponse from api2 it goes to api1 reponse and gets a reponse as undefined
useEffect(() => {
api1();
api2();
}, [])
const api1 = async () => {
try {
var requestModel = JSON.stringify({ UserId: userid, MenuName: menuname });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.put(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
//setapidata(response.data);
}
});
} catch (error) {
console.error(error.message)
}
}
const api2= async () => {
try {
var requestModel = JSON.stringify({ UserID: userid });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.post(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
setapidata(response.data);
GetApis();
}
});
} catch (error) {
console.error(error.message)
}
}

If you want to wait for the api1 to execute before api2 is called you need to change the code for useEffect as below
useEffect(async() => {
await api1();
await api2();
}, [])
or
useEffect(() => {
api1().then(() => api2());
}, [])
To handle errors properly use try-catch block inside the useEffect if using await or use catch block if using .then
Also, another suggestion, if you are using a function inside useEffect make sure either the function is defined inside the same useEffect block or it is memorized either via useCallback or useMemo

Related

How can I send different request in intercepter?

I'm trying to send different request in interceptor
I want to send accessToken in request header authorization for every request except one case
so I write this code in interceptor request.use
config.headers = {authorization: `Bearer ${accessToken}`};
but if this error occurred
error.response.data.code === 'expired'
I want to send refreshtoken in header authorization not accesstoken
so I write this code in interceptor.response.use.error
const { data } = await axios.post(
`${Config.API_URL}/user/refreshToken`,
{},
{ headers: { authorization: `Bearer ${refreshToken}` } }
);
this is my code
useEffect(() => {
axios.interceptors.request.use(async (config: any) => {
const accessToken = await EncryptedStorage.getItem("accessToken");
config.headers = { authorization: `Bearer ${accessToken}` };
return config;
});
axios.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const {
config,
response: { status },
} = error;
if (status === 419) {
if (error.response.data.code === "expired") {
const originalRequest = config;
const refreshToken = await EncryptedStorage.getItem("refreshToken");
const { data } = await axios.post(
`${Config.API_URL}/user/refreshToken`,
{},
{ headers: { authorization: `Bearer ${refreshToken}` } }
);
return axios(originalRequest);
}
}
return Promise.reject(error);
}
);
}, [dispatch]);
how can i fix my code?
if i use my code if error.response.data.code === 'expired'
the headers.authorization accesstoken is still being requested.
Make it so your request interceptor only sets a default authorization header without overriding anything already present
axios.interceptors.request.use(async (config) => {
const accessToken = await EncryptedStorage.getItem("accessToken");
return {
...config,
headers: {
authorization: `Bearer ${accessToken}`,
...config.headers
}
}
});
You could also avoid making the getItem() request entirely which might save a little time
axios.interceptors.request.use(async (config) => {
if (!config.headers.authorization) {
config.headers.authorization = `Bearer ${await EncryptedStorage.getItem("accessToken")}`
}
return config;
});

Return from module is undefined

Hi I made a module and when I try to return the song name it is just undefined, the console.log just before it works though so I'm a little confused. The line after console.log(`"${songName}" by ${artistsList}`) is where the issue is, I try to return "${songName}" by ${artistsList} but the return is just undefined so I am a little stuck on why
Code: (This is the spotify.js module)
I call it with const Spotify = require("./spotify.js"), everything works up until I need to just return the song name using the Spotify.request() function
const axios = require("axios");
module.exports = {
token: "",
ref: "",
refresh: function () {
axios({
method: "post", //you can set what request you want to be
url: "https://accounts.spotify.com/api/token",
data:
`grant_type=refresh_token&refresh_token=${this.ref}`,
headers: {
Authorization:
"Basic ",
"Content-Type": "application/x-www-form-urlencoded"
}
}).then(response => {
this.token = response.data.access_token
console.log(`Successfully refreshed token ${module.exports.token}`);
});
},
analyseSong: function (data) {
console.log(data)
const x = data;
//console.log(x)
if (x.is_playing) {
const songNameMatch = x.item.name.split("(");
var songName = x.item.name;
try {
const letter = songNameMatch[1].charAt(0);
letter.toLowerCase() == "f" ||
songNameMatch[1].toLowerCase().match(/^with/)
? (songName = songNameMatch[0].trim())
: false;
} catch (err) {
false;
}
var artistArray = [];
var artist;
const artists = x.item.artists;
//console.log(token)
for (artist in artists) {
artistArray.push(x.item.artists[artist].name);
}
//console.log(artistArray)
const artistsList = artistArray.join(", ");
//console.log(artistsList)
//console.log(`Currently playing: ${songName} - ${artistsList}`);
console.log(`"${songName}" by ${artistsList}`)
return `"${songName}" by ${artistsList}`;
} else {
return `Not currently listening to a song`;
}
},
request: function () {
axios
.get("https://api.spotify.com/v1/me/player/currently-playing", {
headers: { Authorization: `Bearer ${this.token}` }
})
.then(function (response) {
module.exports.analyseSong(response.data);
})
},
}
So I'm doing X=Spotify.request() trying to get the song name as X so I can output using IRC chat
There are a couple problems. .request() has no return value at all. So, it will never return anything other than undefined. You can fix that like this by adding two return statements, the first to return the promise itself and the second to make the return value from analyseSong() be the resolved value of that promise:
request: function () {
return axios
.get("https://api.spotify.com/v1/me/player/currently-playing", {
headers: { Authorization: `Bearer ${this.token}` }
})
.then(function (response) {
return module.exports.analyseSong(response.data);
})
},
Now Spotify.request() will return a promise that will resolve with the value returned from .analyseSong(response.data). You would use that promise like this:
Spotify.request().then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});

Why is react not posting res.json() to console?

I have tried so many thing but my react app is not recieving jsonData variable or res as a return from the node app. The app is working and printing to console on the node side but I can't get it to print onto the react side.
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
const returnText = res.json();
console.log(returnText);
return res.json();
})
.then((jsonData) => {
console.log(jsonData);
return;
})
.catch((error) => {
console.log("got errr while posting data", error);
});
};
I edited out the api and api key.
var fetch = require('node-fetch');
exports.vehicle = (req, res) =>{
let status;
const { data, data2 } = res.body;
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
};
fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
.then((res) => {
status = res.status;
return res.json()
})
.then((jsonData) => {
console.log(jsonData);
console.log(status);
return jsonData
})
.catch((err) => {
// handle error
console.error(err);
});
res.send(req.body);
}
Working code thanks for the help:
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
console.log(res.data);
return;
})
.catch((error) => {
console.log("got err while posting data", error);
});
};
Node solution in comments.
The functions inside your then() statements need to return data e.g. then((res) => {return res.json()})
You have two problems here...
Client-side, you seem to be mixing up an Axios response with a fetch() Response. You want res.data, not res.json(). Since you've tagged this with reactjs, here is where you would set the data to a state value, eg
axios.post(...).then(res => {
setSomeState(res.data)
})
Server-side, you aren't waiting for your fetch request to complete. I'd recommend using an async function
exports.vehicle = async (req, res) => {
try {
const { data, data2 } = req.body
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
}
// don't mix up the Express "res" with the fetch "response"
const response = await fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`)
}
res.json(await response.json()) // respond with the data
} catch (err) {
console.error(err)
res.status(500).send(err)
}
}

Execute function from object property

i have a little problem with my code.
My expectation is, when i get the object reqHeaders to the function getQueryData
i want that the property UUID will execute the function createToken().
currently, when i running the program, it happens only at the init( first time ).
const createToken = () => {
// some logics...
return `${token}`;
};
const reqHeaders = {
UUID: **createToken()**,
"Content-Type": "application/json;charset=UTF-8"
};
const getQueryData = query => {
return axiosInstance
.post("/someAddress", { selectQuery: query }, { headers: **reqHeaders** })
.then(response => {
// some logs...
return response.data;
})
.catch(error => {
//some logs....
return error;
});
}
};
module.exports = getQueryData;
thank you,
Raz.
The solution is to move the object creation inside the body of the function.
const createToken = () => {
// some logics...
return `${token}`;
};
const getQueryData = query => {
return axiosInstance
.post("/someAddress", { selectQuery: query }, { headers: {
UUID: **createToken()**,
"Content-Type": "application/json;charset=UTF-8"
} })
.then(response => {
// some logs...
return response.data;
})
.catch(error => {
//some logs....
return error;
});
}
};
module.exports = getQueryData;
Now each time you run the function new req headers will be created and hence the UUID. What you did previously created an object once and then use the same object for each function call.

How to receive re-requested data when data requested by mounted() is re-requested by aixos interceptor

the code below is the first request for get list data
mounted() {
this.getList()
},
methods: {
handleClick(row) {
console.log(row.id)
console.log(row.url)
this.$router.push({ name: 'Main', query: { id: row.id } })
},
getList() {
axios
.get('/api/v1/requests/all', {
params: {
userId: this.$store.state.userInfo.id,
},
})
.then(response => {
let moment = require('moment')
for (var item of response.data.data) {
item.createdAt = moment(item.createdAt).format(
'YYYY-MM-DD HH:mm:ss',
)
}
this.items = response.data.data
})
.catch(error => {
console.log(error)
})
}
my interceptor
axios.interceptors.response.use(
function (response) {
return response
},
async function (error) {
const originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true
sessionStorage.removeItem('access-token')
let headers = {
grant_type: 'refresh_token',
Authorization: sessionStorage.getItem('refresh-token'),
}
axios
.post('/api/v1/users/refresh_token', {}, { headers: headers })
.then(response => {
let token = response.data.data
sessionStorage.setItem('access-token', token)
originalRequest.headers['Authorization'] = token
originalRequest.headers['grant_type'] = 'grant_type'
return axios.request(originalRequest)
})
.catch(error => {
console.log(error)
alert('blablabla.')
})
}
return Promise.reject(error)
},
)
the flow is i understand
1.token expired
2.move to list page
3.mounted hook is request data
4.getList -> axios get('~~request/all')
5.interceptor->axios post('~~~refresh_token')
6.re request with new token(request/all)
7.re request is 200, but not update list page
i'd really appreciate your help :)
Seems like you need to return the second request (await for result and return). Right now the result of second request seems to be ignored
axios.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true;
sessionStorage.removeItem("access-token");
let headers = {
grant_type: "refresh_token",
Authorization: sessionStorage.getItem("refresh-token"),
};
const [secondError, res] = await axios // await here
.post("/api/v1/users/refresh_token", {}, { headers: headers })
.then(async (response) => {
let token = response.data.data;
sessionStorage.setItem("access-token", token);
originalRequest.headers["Authorization"] = token;
originalRequest.headers["grant_type"] = "grant_type";
return [null, await axios.request(originalRequest)];
})
.catch((err) => {
console.log(err);
alert("blablabla.");
return [err, null];
});
// Handle here
if(secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
return Promise.reject(error);
}
);
The above solution worked for me perfectly. here's the modified code that I used for my requirement.
export default function axiosInterceptor() {
//Add a response interceptor
axios.interceptors.response.use(
(res) => {
// Add configurations here
return res;
},
async function (error) {
const originalRequest = error.config;
let secondError, res
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
[secondError, res] = await axios({
method: "POST",
url: `${baseURL}/account/token/refreshtoken`,
withCredentials: true,
headers: { "Content-Type": "application/json" },
})
.then(async (response) => {
//handle success
return [null, await axios.request(originalRequest)];
}).catch(function (error) {
console.error(error)
});
}
if (secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
);
}

Resources