I am running into a really frustrating issue. Where a simple json constant on the express server is sent as a json object, but when receiving this object, and trying to extract the errors from it on the client, the json object from the server comes through as undefined and for the life of me, I can't figure out why.
It seems that changing res.status(400).json(errors); to res.json(errors); from the server and extracting the error data from the client code block where isValid is true, I am able to get the error messages - therefore, sending the 400 status, may have something to do with it.
Has anyone else run in to this issue? i appreciate any suggestions on how to resolve.
Express - api.js
if( isValid ) {
res.json({success: true});
} else {
const errors = { username: 'This field is required',
email: 'Email is invalid' };
res.status(400).json(errors);
}
SignupForm Component
this.setState({errors: {}, isLoading: true});
this.props.userSignupRequest(this.state).then(
() => {
this.props.history.push('/');
},
({data}) => {
console.log(data); //undefined
this.setState({errors: data, isLoading: false})
}
)
SignupAction.js
import axios from 'axios';
export function userSignupRequest(userData) {
return dispatch => {
return axios.post('http://myhost/api/signup', userData);
}
}
As per the Axios manual:
When using catch, or passing a rejection callback as second parameter of then, the response will be available through the error object as explained in the Handling Errors section.
So:
this.props.userSignupRequest(this.state).then(
() => {
this.props.history.push('/');
},
error => {
const {data} = error.response;
console.log(data);
this.setState({errors: data, isLoading: false});
}
)
Related
I am creating a mern authentication project and am stuck on a problem. When the information is sent in my register page an add user function is called on the front end
async function addUser(user) {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
await axios.post("/users/register", user, config);
} catch (err) {}
}
Which calls this function in my back end
exports.addUser = async (req, res, next) => {
try {
const { name, email, password } = req.body;
let errors = [];
// Check required fields
if (!name || !email || !password) {
errors.push("All Fields Need To Be Filled");
}
//Check Password Length
if (password.length < 6) {
errors.push("Password Needs To Be At Least 6 Characters Long");
}
if (errors.length > 0) {
return res.status(201).json({
success: false,
errors,
});
} else {
return res.status(201).json({
success: true,
data: req.body,
});
}
} catch (error) {
return res.status(500).json({
success: false,
error,
});
}
};
And my route
router.route("/register").post(addUser)
My question is how to get the json from the node.js function in react.js. For example if there is an error how do I get this
return res.status(201).json({
success: false,
errors,
in my front end. Since this is not a get request I can't access the errors with
const res = await axios.get("/");
If anybody knows what to do it would mean a lot if you helped
First off, I would recommend changing the code as a response of 201 is considered a successful "Created" response (mozilla docs).
Then, if you are using axios, you need to create an interceptor in your frontend side that will handle the response errors. Check the documentation here.
Basically you can leave the response part empty, and then throw an exception in the error function so you can handle it from the place you are making the call.
axios.interceptors.response.use(
(response) => response,
(error) => {
// you can handle the error here or throw an error
throw error;
}
})
I recommend that you leave the interceptor and the base axios call in a separate file so it's easier for you to handle the calls and the interceptor.
I use openweathermap API to get forecast. App is based on ReactJS and Redux. I have a problem with catch errors. I want to create alert for users when searched city doesn't exists in database.
So, I have action like below:
export function fetchWeather (city) {
const url = `${ROOT_URL}&q=${city}`;
const request = axios.get(url);
return (dispatch) => {
request
.then(({data}) => {
dispatch({type: FETCH_WEATHER, payload: data})
})
.catch((error) => {
dispatch({type: FETCH_WEATHER_ERROR, payload: error})
});
};
And my reducer:
import { FETCH_WEATHER, FETCH_WEATHER_ERROR } from '../actions/index';
export default function (state = [], action) {
switch (action.type) {
case FETCH_WEATHER:
console.log(action.payload) //I receive object, so it's ok
return [...state, action.payload];
case FETCH_WEATHER_ERROR:
console.log(action.payload) // I receive just info in console "Error: Request failed with status code 404"
return state;
}
return state;
}
So, it works properly but I'm curious how to get proper object in error part to simple show alert with message info what happened wrong. Because when I check in inspector tab (Networks) there is nice object in response:
{cod: "404", message: "city not found"}, but in console.log(action.payload) I have just info, no object, array... Why are these things different? How to get proper value of error response to show error message?
It looks like the API will always return 200 (success) when the connection works even though there is a 401 not allowed or 404 not found. Check out the following url in your dev tools network tab:
http://samples.openweathermap.org/data/2.5/weather?q=nomatterNoApiKey
So anything going into catch is actual network problem.
request
.then((response) => {
if(response.cod===200){
dispatch({type: FETCH_WEATHER, payload: response.data});
}else{
dispatch({type: FETCH_WEATHER_ERROR, payload: response.message});
}
})
You have to make sure that is the correct way to use the API and still have to deal with network errors.
I use axios to make call to the backend server. And with redux-saga I can control the side effect from the server easily.
import {call, put, takeEvery} from "redux-saga/effects";
import {REQUEST_FAILED, REQUEST_SUCCESS, ROOT_URL, SUBMIT_USERNAME_PASSWORD} from "../../constants";
import axios from "axios/index";
const shootApiTokenAuth = (values) => {
const {username, password} = values;
return axios.post(`${ROOT_URL}/api-token-auth/`,
{username, password});
};
function* shootAPI(action) {
try {
const res = yield call(shootApiTokenAuth, action.payload);
const {history} = action.payload;
yield put({
type: REQUEST_SUCCESS,
payload: res
});
history.push('/companies'); //push user to `/companies` page
} catch (err) {
yield put({
type: REQUEST_FAILED,
payload: err
});
}
}
export function* watchSubmitBtn() {
yield takeEvery(SUBMIT_USERNAME_PASSWORD, shootAPI);
}
Problem:
When the backend server is down. It does not return any error back to me. And browser will raises an error Failed to load resource: net::ERR_CONNECTION_REFUSED
I have seen previous answer on callback method, but I prefer axios and redux-saga not callback
I had tried console.log(err). And I still searching they way to grab the error message and differentiate it from server response error.
Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Question:
How can I use axios and redux-saga to catch the err?
If you put the try/catch around the axios request itself, then you can get a bit more granularity on the cause.
https://gist.github.com/fgilio/230ccd514e9381fafa51608fcf137253
You probably want to have a custom error format and an error reducer that handles the different types of errors appropriate. For example if you got a response you could parse it and add it to the error, else you know there is an application level error which you would handle with an 'Oops' page or something like that.
case REQUEST_FAILED:
//Probably it can failed by 2 reason
//1. 404 from server
//2. network is down
if (action.payload.response === undefined) {
return {
token: undefined,
message: 'Network is down',
isAuthenticated: false,
statusCode: 406
}
} else {
const tmp = action.payload.response.request.response;
const tmp2 = JSON.parse(tmp);
return {
token: undefined,
message: tmp2.non_field_errors[0],
isAuthenticated: false,
statusCode: action.payload.response.status
};
}
Below is my connection request code :
doLogin(this.login).then(response => {
var token = response.data.token;
localStorage.setItem('AUTH_TOKEN', JSON.stringify(token));
this.$router.push({name: 'Devices'});
});
}).catch(error => {
console.log(error.response.data.message);
});
the catch() part works fine for http errors (like 400, 404, 403..etc). But when my server is offline this script just throws net::ERR_CONNECTION_REFUSED. Is there any way to handle this error and let the front-end user know that the server is currently offline.?
Here is the doLogin() function just in case,
function doLogin(data) {
const url = 'http://localhost:3000/authenticate';
return axios.post(url,data);
}
You can try this in the catch part:
catch(error => {
if (!error.response) {
// network error
this.errorStatus = 'Error: Network Error';
} else {
this.errorStatus = error.response.data.message;
}
})
You may use interceptors:
axios.interceptors.response.use(
response => {
return response
},
error => {
if (!error.response) {
console.log("Please check your internet connection.");
}
return Promise.reject(error)
}
)
You should do the same validation that #chithra pointed out in the .then() because i'm having a weird issue when testing requests with my servers down, the "response" comes as if it was a success.
Also, on the .then() do it with response.status instead of response.error
By using npm; a standard package manager for the JavaScript runtime environment Node.js.
With npm:
npm i axios
Next, you should import Axios in your src/App.vue file
import axios from 'axios';
you will need to call it on a lifecycle hook. Here we will use the beforeCreated() lifecycle hook, this is because we will be able to retrieve sensitive data and events that are active with the beforeCreated hook.
data() {
return {
network: false,
}; },
beforeCreate() {
axios
.get("http://localhost:13172/api/product/getproducts")
.then((response) => {
console.log(response);
this.network = true;
})
.catch((error) => {
console.log(error), (this.network = false);
}); }
Right now I want to save user token after the user login successful.
Here is my code:
onPress(){
return axios.post('https://api.example.net/v1/user/auth/login', {
email: this.state.email,
password: this.state.password,
}, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
}).then((response) => {
AsyncStorage.setItem('token', response.data.login._cxz, () => {
console.log('success');
});
this.props.navigator.immediatelyResetRouteStack([{name: 'tweets'}]);
})
.catch((error) => {
this.setState({errorMessage: error.response.data.message});
});
}
I already make sure that response.data.login._cxz has a value.
Right until here is working. the login will redirect me to tweets route.
On my tweets.js:
constructor(props){
super(props);
this.state({token : ''});
}
componentWillMount() {
AsyncStorage.getItem('token', (err, value) => {
console.log(value);
})
}
I just simple console.log it to view if the token is saved or not.
But everytime login is done (the success log is appear). I always got this error when enter my tweets:
Any solution?
Thanks.
What is most likely happening is that the then callback is throwing an error at navigator.immediatelyResetRouteStack:
.then((response) => {
AsyncStorage.setItem('token', response.data.login._cxz, () => {
console.log('success');
});
this.props.navigator.immediatelyResetRouteStack([{name: 'tweets'}]);
})
.catch((error) => {
this.setState({errorMessage: error.response.data.message});
});
The error is then caught in the catch block, but because the error is a normal JavaScript Error and not an axios error, it does not have response property, and therefore trying to access error.response.data causes the undefined error.
The easy way to detect the kind of error is to duck-type it: If the error has a response, then it's an axios error, otherwise another error:
.catch((error) => {
if (error.response && error.response.data) {
this.setState({errorMessage: error.response.data.message});
} else {
this.setState({errorMessage: error.message});
}
});
The error caused by immediatelyResetRouteStack is probably coming from the React render pass that is synchronously executed on the same call stack. Once you fix the broken .catch you'll see what the error message is, but a good guess for a culprit in your limited code sample is:
this.state({token : ''});
Which should be an property assignment, instead of a method call:
this.state = {token : ''};