i have created a asyncthunk, but when status code is 400, the result of request is still fulfilled, which method is to handle a 400 error with createasyncthunk and fetch api?
This is a action code:
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import authService from "./auth-service";
// Get user from localStorage
const user = JSON.parse(localStorage.getItem("user"));
const initialState = {
user: user ? user : "",
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Register user
export const register = createAsyncThunk(
"auth/signup",
async (user, thunkAPI) => {
try {
return await authService.register(user);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Login user
export const login = createAsyncThunk("auth/login", async (user, thunkAPI) => {
try {
return await authService.login(user);
} catch (error) {
const message =
(error.response && error.response.data && error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
});
export const logout = createAsyncThunk("auth/logout", async () => {
await authService.logout();
});
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
reset: (state) => {
state.isLoading = false;
state.isSuccess = false;
state.isError = false;
state.message = "";
},
},
extraReducers: (builder) => {
builder
.addCase(register.pending, (state) => {
state.isLoading = true;
})
.addCase(register.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.isSuccess = false;
state.user = "";
})
.addCase(register.fulfilled, (state, action) => {
state.isLoading = false;
state.isError = false;
state.isSuccess = true;
state.message = action.payload;
})
.addCase(login.pending, (state) => {
state.isLoading = true;
})
.addCase(login.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.user = action.payload;
})
.addCase(login.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
state.user = "";
})
.addCase(logout.fulfilled, (state) => {
state.user = "";
});
},
});
export const { reset } = authSlice.actions;
export default authSlice.reducer;
This is a service code:
import React from 'react'
import Cookies from 'js-cookie'
const API_URL = "http://localhost:5000/api/auth/";
const token = Cookies.get('XSRF-Token')
// Register user
const register = async (userData) => {
const response = await fetch(API_URL "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Login user
const login = async (userData) => {
const response = await fetch(API_URL "login", {
method: "POST",
credentials: 'include',
body: JSON.stringify(userData),
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
// Logout user
const logout = () => {
localStorage.removeItem("user");
};
const authService = {
register,
logout,
login,
};
export default authService;
The problem is both register and login action, return a fulfilled even if the code of post request is 400 and my intention is send a message about error
CodePudding user response:
Your code doesn't do anything if response.ok
is not truthy. That's what will happen when you get a 4xx status.
So, for example, in this code:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
}
};
You just allow the async
function to have an undefined
return value if response.ok
is not truthy. That will resolve the promise, with an undefined
resolved value.
Perhaps, you want to turn any non-2xx status into a rejection like this:
// Register user
const register = async (userData) => {
const response = await fetch(API_URL "signup", {
method: "POST",
credentials: 'include',
headers: {
'X-CSRF-Token': token,
'Accept': "application/json",
"Content-Type": "application/json",
},
// body: JSON.stringify(userData),
});
const responseData = await response.json();
if (response.ok) {
localStorage.setItem("user", JSON.stringify(responseData));
return responseData;
} else {
// reject the promise
throw new Error(`status code ${response.status}`)
}
};
You would probably want to do something similar for all your uses of fetch()
.
Since I find that I want this to be the standard behavior when making requests, I have my own fetchWrapper()
function that automatically converts any non-2xx status to a promise rejection so I don't have to code that into every use of fetch()
.