Redux toolkit handling axios undefined response - reactjs

I'm using redux toolkit and im sending request to Api.
In the example below, we try to find user by some shortId, if there is no user found, server respond with 404 status code.
Server side:
class Controller {
...
public sendInvitationHandler = async (
req,res
) => {
try {
const senderId = res.locals.user.id;
const { username, shortId } = req.body;
const user = await this.userService.findUserByShortId({
shortId,
username,
});
//I want this message in redux error message
if (!user) return res.status(404).send('No user found!')
const response = await this.friendService.sendInvitation({
senderId: senderId ,
receiverId: receiverId,
});
res.send(response);
} catch (error) {
res.status(400).send(error);
}
};
User service function:
...
public findUserByShortId=async({shortId,username})=>{
const user= await this.users.findOne(
//some logic
)
return user
}
Client side :
...
export const sendInvitationHandler = createAsyncThunk(
"friends/sendInvitation",
async ({ username, shortId }, thunkApi) => {
try {
if(!username || !shortId ) return
const response= await friendService.sendInvitation({ username, shortId });
if(!response) throw new Error()
return response
} catch (error: any) {
const message =
error?.response?.data?.message || error.message || error.toString();
return thunkApi.rejectWithValue(message);
}
});
I cant figure out how to pass an error from backend to redux state.In reducer response is undefined because we dont find any user. If i dont throw any error when there is no response, then reducer is fullfiled because it is not an error to redux.
I get error message:
'Cannot read properties of undefined (reading 'data')'

Related

Failing to call two APIs one after another and redirecting the user to another page

I'm using Reactjs for my frontend and Springboot and Firebase for my backend. Basically, when a user registers for an account, I will call two APIs to post the account to both Firebase and my Springboot server, the reason being that I need to make use of the user data collected inside my own Springboot server.
The problem I'm facing is that after a user registers for an account, the Springboot API is not called after Firebase API is called. (I call the Firebase API first and then the Springboot one) It seems to me that after calling the Firebase API, everything stops and the code doesn't go any further, thus calling no more API.
How do I make sure that I can call both APIs one after another and then redirect the user to the next page without any interference?
Registration on submit in Reactjs:
const handleOnSubmit=(event: React.FormEvent<HTMLFormElement>)=> {
if (password !== secondPassword) {
setPasswordsMatched(false);
console.log("passwords matched when password!==secondPassword:" + passwordsMatched);
} else if(!username){
setUsernameExists(false);
}else if(!email){
setEmailExists(false);
}else if(!password||!secondPassword){
setPasswordExists(false);
}else{
if(subscribedStatus){
let subscribed:string="subscribed";
firebaseAuthServiceSignUpWithEmailAndPassword(username,email,password,subscribed,handleSignupSuccess);
}else{
let subscribed:string="unsubscribed";
firebaseAuthServiceSignUpWithEmailAndPassword(username,email,password,subscribed,handleSignupSuccess);
}
}
}
//This is the callback function put inside the Firebase API to see if Firebase accepts the registration. If yes, the user is redirected to "/verification-email"
const handleSignupSuccess=(signupStatus:boolean)=>{
setSignupSuccess(signupStatus);
if(signupStatus){
firebaseAuthServiceEmailVerification(setEmailVerificationSent);
navigate("/verification-email");
}
}
Firebase API:
export const firebaseAuthServiceSignUpWithEmailAndPassword= (username:string,email: string, password: string, subscribed:string,callback: (isSuccess:boolean)=>void) =>{
const auth = getAuth();
createUserWithEmailAndPassword(auth, email, password)
.then(async ( userCredential) => {
// Signed in
const user = userCredential.user;
await postAccount(username, email, password, user.uid, subscribed);
callback(true);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
callback(false);
// ..
});
}
Springboot API:
export const postAccount=(username:string,email:string,password:string,firebaseUid:string,subscribedStatus:string)=>{
axios.post(`http://localhost:8080/user/${username}/${email}/${password}/${firebaseUid}/${subscribedStatus}`
)
.then((res)=>{
}).catch((error)=>{
console.log(error);
})
}
You mostly need a return statement in postAccount function
Quick fix
export const postAccount=(username:string,email:string,password:string,firebaseUid:string,subscribedStatus:string)=>{
// return here
return axios.post(`http://localhost:8080/user/${username}/${email}/${password}/${firebaseUid}/${subscribedStatus}`
)
.then((res)=>{
return res; // may be return here too
}).catch((error)=>{
console.log(error);
})
}
// async function
const handleOnSubmit= async (event: React.FormEvent<HTMLFormElement>)=> {
if (password !== secondPassword) {
setPasswordsMatched(false);
console.log("passwords matched when password!==secondPassword:" + passwordsMatched);
} else if(!username){
setUsernameExists(false);
}else if(!email){
setEmailExists(false);
}else if(!password||!secondPassword){
setPasswordExists(false);
}else{
if(subscribedStatus){
let subscribed:string="subscribed";
// wait till completion
await firebaseAuthServiceSignUpWithEmailAndPassword(username,email,password,subscribed,handleSignupSuccess);
}else{
let subscribed:string="unsubscribed";
// wait till completion
await firebaseAuthServiceSignUpWithEmailAndPassword(username,email,password,subscribed,handleSignupSuccess);
}
}
}
Slightly better fixs:
With multiple API call its better to use async calls
export const firebaseAuthServiceSignUpWithEmailAndPassword = async (username:string, ...) => {
try {
const auth = getAuth();
const userCredentials = await createUserWithEmailAndPassword(auth, email, password)
const user = userCredential.user;
const res = await postAccount(username, email, password, user.uid, subscribed);
// may be some extra checks
//if (res.success) {
// callback(true);
//}
callback(true);
} catch(error: any) {
// handle error
callback(false);
}
}
export const postAccount = async (username: string, ...) => {
return await axios.post(`http://localhost:8080/user/${username}/${email}/${password}/${firebaseUid}/${subscribedStatus}`)
}
Hope it helps in someway

Return Postman error message to user on failed login/reg React-Native

My backend is set up with validations, which I want to return to the user on failed attempts.The top picture is what I am currently returning. The picture below that one (what my postman returns) is one such error message I want to return to a user on a failed login attempt in my try/catch block. I would prefer to do this via the Alert.alert() method. The following is my loginUser code:
enter code hexport interface LoginRequest {
name: string;
pass: string;
}
export const loginUser = async (
request: LoginRequest,
onSuccess: (user: User) => void,
onError: (error: any) => void,
) => {
console.log(request);
try {
await logout();
const loginResponse: AxiosResponse<LoginResponse> = await login(request);
const loginResponseData: LoginResponse = loginResponse.data;
console.log('userAuth: ', loginResponseData);
await AsyncStorage.setItem('access_token', loginResponseData.access_token);
await AsyncStorage.setItem('logout_token', loginResponseData.logout_token);
await AsyncStorage.setItem('csrf_token', loginResponseData.csrf_token);
const userId = loginResponseData.current_user.uid;
const userResponse: AxiosResponse<User> = await getUser(userId);
console.log('user response:', userResponse);
onSuccess(userResponse.data);
} catch (error: any) {
console.log('Login error: ' + JSON.stringify(error));
console.log();
onError(error);
}
};
You can access the body of the response of an Axios 4xx error with error.response.data. Simply use the below line:
onError(error?.response?.data?.message || error);

Can not read property 'msg' of undifined

const onSubmit = async () => {
showError(false)
try{
await axios.post("http://localhost:9005/api/Users", user);
// history.push("/")
handleClose()
props.snackbarShowMessage(`User Added Successfully `)
data()
formReset()
}catch(error){
showError(true)
console.log('asdfg',error)
props.snackbarShowError(error.response.data.error[0].msg)
}
};
Assign response to variable , then check its response status.
you can verify this by using...
const x = await axios.post("http://localhost:9005/api/Users", user);
console.log(x.statusCode);
Note that try catch will handle react error not axios error..

Unhandled Rejection (TypeError): user.getSession is not a function

I am using AWS amplify in my app, I implemented a login function with google. But after login, i get this error Unhandled Rejection (TypeError): user.getSession is not a function .
I have used Auth.federatedSignIn function for the login.
Here is my code:
const responseGoogle = async (response) => {
try {
setLoading(true);
const user = {
name: response.profileObj.name,
email: response.profileObj.email
};
const password = await Auth.forgotPassword(user.email);
let expires_at = addMilliseconds(new Date(), 3600 * 1000).getTime();
const result = await Auth.federatedSignIn(
'google',
{ token: response.tokenId, expires_at },
user
);
console.log(result);
console.log('heree');
history.push('/classes/google');
setLoading(false);
setUserInfo(loadedUsers, email);
} catch (error) {
console.log(error);
if (error.message !== `Cannot read property 'name' of undefined`) {
enqueueSnackbar(error.message, { variant: 'error' });
}
setLoading(false);
}
};
The response is the response that I get from google.
does anyone know why I am getting this error? appreciated any type of help. Thanks
Firstly you have to check all restrictions auth is at the config json when you create auth function
The second thing is you have to pass three parameters in order to change passwords such as
User
Is the user session and you can get it by fetch the current sesion token and auth data.
Oldpassword
New Password

Possible Unhandled Promise Rejection: Error: Actions must be plain objects. Use custom middleware for async actions

I have a function that is meant to perform various asynchronous actions based on the set inputs. Here is my function:
const generalApiRequest =(requestUrl, urlType, data={},actionDispatch) =>{
return function(dispatch, getState){
console.log(dispatch);
adminId = getState().authentication.adminId;
token = getState().authentication.token;
return hitUrl(requestUrl,urlType, dispatch, data).then((response)=>{
try{
if(response.status === 200){
//dispatch(actionDispatch(response.data));
actionDispatch();
}
else{
console.log("Wrong response",response);
if(response.status === 401){
console.log('login again, auth failed');
dispatch(authFailed());
}
}
}
catch(error){
console.log(error);
}
}
,(error)=>{console.log(error)})
}
};
Here is also hitUrl() which is needed for the function :
const hitUrl= async function(requestUrl, urlType,dispatch, data={}){
try {
//const requestUrl = apiUrl+ 'application/fetch-dashboard-data'+`/{$adminId}`;
if(urlType === "get"){
response = await axios(requestUrl,header(token));
}
else {
response= await axios.post(requestUrl, data, header(token));
}
return response;
} catch (error) {
console.log(error);
console.log("error status", error.response.status);
try{
if(error.response.status === 401){
dispatch(authFailed());
}
}
catch(newError){
console.log(newError)
}
}
}
I also have the function processApplicant()
export const processApplicant=(data)=>{
let requestUrl;
let urlType = "post";
let message;
message = "The user has been successfully deleted"
requestUrl = apiUrl+ 'application/process/delete';
let actionDispatch= triggerSuccess(message);
generalApiRequest(requestUrl,urlType, data, actionDispatch);
}
Now I dispatched the action below in my react component
dispatch(processApplicant({adminId: 2, comment: "No comments", trigger: "Pick", userId: 3}));
On doing this I get the error in the title above (Possible Unhandled Promise Rejection: Error: Actions must be plain objects. Use custom middleware for async actions).
I have redux thunk as middleware and it works fine for other request. What I'm I doing wrong please?
Your processApplicant is not set correctly.
export const processApplicant = (data) => {
return (dispatch) => {
let requestUrl;
let urlType = "post";
let message;
message = "The user has been successfully deleted"
requestUrl = apiUrl + 'application/process/delete';
let actionDispatch = triggerSuccess(message);
dispatch(generalApiRequest(requestUrl, urlType, data, actionDispatch));
}
}

Resources