Handling API calls with async/await in React Native - react-native

I want to have a separate file for API calls -
APIHandler.js
const loginAPI = 'https://..../login';
export async function login(emailAddress, pass) {
const reqOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: emailAddress,
password: pass,
})
};
let response = await fetch(loginAPI, reqOptions);
return response;
}
Now in my login.js, I want to do so:
onLoginPressed = async () => {
let response = login(this.state.email, this.state.password)
if (response.status >= 200 && response.status < 300) {
//Login success
} else {
//Login error
}
}
But this doesn't seem to work. After I press login, nothing happens. Can anyone tell me where I am doing wrong.

Since login is an async function, and you want to wait for the response to be returned from login, you have to await the call to login too:
let response = await login(this.state.email, this.state.password)
login itself awaits for the fetch call to finish. So for you to wait for login to finish, you must await it. If you don't, login returns a promise, which as you observed, is not the response object from the request.

Related

Why Axios is not providing response header when app is opening second time?

Here is my API request
const getData= async () => {
const cookie='workid_token=eyJra4rgrtF7SnlSETjIGrFYQy-P2SFmlE6A.Tw_rx0Ut_Kj9zLWRQ9X23w';
const qs = require('qs')
let body = qs.stringify({
gid: '1196'
})
await axios.post(
'https://www.google.com', body,
{
headers: {
'Cookie': cookie,
'Content-Type': 'application/x-www-form-urlencoded',
},
},
).then(response => {
console.log('data', response);
if (response.data.status === '1') {
const PHPSESSID = response.headers['set-cookie'];
var separatedvalue = PHPSESSID[0];
var sessid = separatedvalue.split('; path=/')[0];
}
}).catch(error => {
console.log(error);
});
};
I am implementing Axios API post request in my React Native application. When I run the application first time I am getting set-cookie value in response headers. If I kill the application and I open it second time I am not getting value in set-cookie. Also not receiving response from the API.
Note: I want to receive value from set-cookie all the times.

Why is yield not returning anything in Redux Saga?

I'm trying to use Redux Sagas to handle my login action. This is my sagas.ts:
function* loginUserSaga() {
const user: Login = yield take(actionTypes.LOGIN)
const { username, password } = user.payload;
const { data, status } = yield call(() => login({ username: username, password: password }))
yield put(status === 200 ? loginSuccess(data.token, data.userId) : loginFailed({ message: "Could not log in." }));
}
export function* rootSaga(): Generator {
yield takeLatest(actionTypes.LOGIN, loginUserSaga)
yield takeLatest(actionTypes.POST_DRAWING, postDrawingSaga)
yield takeLatest(actionTypes.GET_WORD_OF_DAY, getWordOfDaySaga)
}
I'm trying to call this login function which sends a POST request using axios as such:
const header = {
"content-type": "application/json",
}
export const login = (data: LoginRequest) => {
return axios.request({
method: "POST",
url: "http://localhost:3001/api/login",
headers: header,
data: data,
});
};
Using the status, I want to put an action, either loginSuccess or loginFailed:
export const loginSuccess = (token: string, userId: number): LoginSuccess => ({
type: actionTypes.LOGIN_SUCCESS,
payload: {
token,
userId
}
})
export const loginFailed = (error: data.Error): LoginFailed => ({
type: actionTypes.LOGIN_FAILED,
error: error
})
Why isn't anything being put? From the Network tab of browser, I can see that my express server is returning a response, but the sagas don't seem to work?
Response from express server:
I've figured out what went wrong.
export const login = async (data: LoginRequest) => {
return await axios.request({
method: "POST",
url: "http://localhost:3001/api/login",
headers: header,
data: data,
});
};
I had to make this login function async, and await the result from the axios request for it to work.

Cancel an axios request, when not having the fetch in useEffect

I am trying to implement the cancel request function for my axios post. I created own js files for the functions and I am importing them into my screens. Here is an example
App.js
cancelToken.current = axios.CancelToken.source()
async function getFeed() {
let x = await service.getUserFeed(user_id, cancelToken);
setData(x); }
getFeed();
return () => {
cancelToken.cancel();
}
},[user_id]);
service.js:
getUserFeed: async (token, user_id, source) => {
let x;
await axios.post(Default.apiEndpoint + 'feed',
{
},
{
cancelToken: source.token,
headers: {
'Accept': "application/json",
'Content-Type': "application/json",
'user_id': user_id,
}
}).then(response => {
x = response.data;
}).catch(error => {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
else {
x = error.response.status;
}
});
return x;
},
If I am calling the request in the hook itself it is working. So I am not even sure, if it is possible, because the request is not triggered, when the user leaves the page. So I would need to cancel the request in the service.js itself (I guess). Did anyone implement that already and can help me here?
Thanks

react-native - check expiration of jwt with redux-thunk middleware before every call to API

For my react-native app I need to make sure that before every fetch request to server the use-case below should be executed
-> check the expire date of token that is saved to redux.
--> If token is not expired, app keeps going on with requested fetch to server
--> If token expired, app immediately makes new request to refresh token without making user knows it. After successfully refreshing token, app keeps going on with requested fetch to server
I tried to implement middleware with redux-thunk, but I do not know whether it's good design or not. I just need someone experienced with redux and react to give me feedback over my middleware code.
This is how I make requests to server oveer my app's component through dispatching the checkTokenAndFetch - action creater.
url = "https://———————";
requestOptions = {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + this.props.token
}
};
dispatch(authActions.checkTokenAndFetch(url, requestOptions))
.then((data) => {
})
here is action creator - checkTokenAndFetch located in authActions.js
file where my actions located
function checkTokenAndFetch(url, requestOptions){
return dispatch => {
if(authServices.isTokenExpired()){
console.log("TOKEN EXPIRED");
authServices.refreshToken()
.then(
refreshToken => {
var arr = refreshToken.split('.');
decodedToken = base64.decode(arr[1]);
newTokenExpDate = JSON.parse(decodedToken).exp;
dispatch(writeTokenToRedux(refreshToken,newTokenExpDate));
},
error => {
Alert.alert("TOKEN refresh failed","Login Again");
Actions.login();
}
);
}
else{
console.log("TOKEN IS FRESH");
}
return authServices.fetchForUFS(url, requestOptions)
.then(
response => {
return response;
},
error => {
}
)
;
}
}
Here is isTokenExpired and refreshToken functions that I call for case of token expire, located in another file named authServices.js.
function isTokenExpired(){
var newState = store.getState();
var milliseconds = (new Date).getTime();
var exDate = newState.tokenExpDate;
return milliseconds>exDate*1000
}
function refreshToken(){
var refreshToken = store.getState();
return fetch('https://—————————', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + refreshToken.token
}
})
.then((response) => {
return response._bodyText;
})
.catch((error) => {
return error;
})
}
and my fetchForUFS function in authServices.js to make a call to server after completeing token-check(refresh) stuff.
function fetchForUFS(url,requestOptions){
return fetch(url, requestOptions)
.then((response) => {
return response.json();
})
.then((responseData) =>{
return responseData;
})
.catch((error) => {
})
}
I've read tons of redux-thunk, redux-promise and middleware documentation and I'm yet not sure whether I am implementing middleware logic truly?

Request Header not being sent as a parameter to API calls

I was trying to make an API call to another domain, which has no-cors enabled.
The API call was made something like this:
let url = `https:sampleApiUrl?params=xxxx`;
console.log("hitting dashboard url")
get(url, token)
.then((resp) => {
console.log("resp", resp)
})
.catch((error) => {
console.log(error)
})
This API call, subsequently calls a 'get' method:
const get = (url, authToken) => {
return baseFetch(url, 'get', false, authToken).then(response => {
if (response.status >= 200 && response.status < 300) {
return response.json();
} else {
const error = new Error(response.statusText);
error.response = response;
throw error;
}
});
}
Now, this get method calls a baseFetch method:
const baseFetch = (url, verb, body, authToken) => {
const request = {
method: verb,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'Access-Control-Allow-Origin': '*',
'credentials': 'include'
},
mode: 'cors'
}
if (authToken){
// adding x-access-token in the request header
request.headers['x-access-token'] = authToken;
}
if (body){
request.body = JSON.stringify(body);
}
return fetch(url, request);
}
Now, when this API call is requested, I can't see the "x-access-token" populated in the browser network call.
No x-access-token in request-headers
Also, I am not sure why I get status code 204 in response.
Calling this API from postman and directly from browser or calling as a curl request, returns the correct response.
Thanks
Looking at the image, you are looking at the headers for pre flight OPTIONS method and not the GET method. The pre flght request is generated by the browser and it never has any custom header. therefore it did not have the x-access-token in its headers.