VueJs auth not passing - javascript

I'm having some problems with authentication with Vue.
I'm trying to check user data and return him if he is validated or not, I'm catching errors as well, but this is meant in case if some other error happens.
This is my code:
loginJWT ({ commit }, payload) {
return new Promise((resolve, reject) => {
jwt.login(payload.userDetails.email, payload.userDetails.password)
.then(response => {
// If there's user data in response
if (response.data.userData) {
// Navigate User to homepage
router.push(router.currentRoute.query.to || '/')
// Set accessToken
localStorage.setItem('accessToken', response.data.accessToken)
// Update user details
commit('UPDATE_USER_INFO', response.data.userData, {root: true})
// Set bearer token in axios
commit('SET_BEARER', response.data.accessToken)
resolve(response)
console.log(response.data.accessToken);
} else {
reject({message: 'Wrong Email or Password'})
}
})
.catch(error => { reject(error) })
})
}
As you see I have 'Wrong Email or Passoword', but this message never showed.
I tried like if(response.status === 200) and else if(response.status === 400) to catch that status and show the message, but no success anyway. Ofc when I put invalid credentials, it's returning 'Request failed with status code 400', but I want to show 'Wrong Email Or password'.
I even tried to check if first gives response status 400 before even check if there is response.data.userData like:
if(response.status == 400){
reject({message: 'Wrong Email or Password'})
}
But still not a success.
What I really want to return is the message that I'm giving from the response, I could just return the message 'something is wrong' in .catch(error), but I can't catch response.data.message like this, because I have message receiving from my backend.
Any ideas on how to resolve it?

Related

Why Request API when error always goes to catch

I have some questions about requesting API from the server. I make a function for request API, the example I have a request API login when the user fills the email wrong, response API is "email or password is wrong!", when I try in postman is success the response but when I try in my code the response always from the catch, not from response API. My code for request API like below
const handleSubmitLogin = async (input) => {
try {
const result = await axios.post(`${BASE_URL}/users/client/login`, input);
if (result.status == 200 || result.status === "success" || result.status == 201) {
await setAuthKey(result.data.data.token);
await setLoggedUser(JSON.stringify(result.data.data));
dispatch(setUserLogin());
dispatch(setDataLogin(result.data.data));
} else {
setModalActive({ status: true, data: result.message });
}
} catch (error) {
console.log(error);
setModalActive({ status: true, data: translations["please.try.again"] });
}
};
when a user fills an email or password wrong, the response is always from the catch response not from the API response. Can anyone give suggestions for this case?
Edit:
This is result from when user wrong password
If your API responds with a non-successful status code (>= 400), Axios will reject the promise and your code will go into the catch block.
You can still access the response data via error.response.data. See Axios - Handling Errors
try {
const result = await axios.post(`${BASE_URL}/users/client/login`, input);
// etc...
} catch (err) {
console.warn("login", error.toJSON());
setModalActive({
status: true,
data: error.response?.data?.message ?? translations["please.try.again"],
});
}
It's important to use optional chaining since the error may not have a response or data depending on what exactly failed.

How do I show message on 403 client side if the email fails to send?

I am trying to show alert message when the email sends or gets failed. If it fails, I'm getting 403 from the backend. But not sure how do I show it here in client-side. If success, I get a 200. Right now, in the case of failure, if I console.log(res)(as you can see below), it shows
res is not defined
Uncaught (in promise) Error: Request failed with status code 403
And in network tab, I get the response. That's alright.
I just want to show it here client side in my react component.
handleClick = (id) => {
axios
.post(`http://localhost:3000/api/v1/users/send-post/${id}`)
.then((res) =>
console.log(res),
res.status === 200 ? alert("Email sent"): null
)
.catch((err) => {
if (err) {
return alert("Sorry, Something went wrong")
}
})
}
The error status is in err.response.status.
Modify
if (err) {
return alert("Sorry, Something went wrong")
}
with
if (err) {
return alert("Sorry, Something went wrong. Status "+ err.response.status)
}
For reference, you check this link https://stackoverflow.com/a/39153411/12680971
You have a comma , after console.log call.
Do next:
.then(res => {
console.log(res);
res.status === 200 && alert("Email sent");
})
Or another variant:
.then(res =>
console.log(res) ||
res.status === 200 ? alert("Email sent") : null
)

Store GraphQL errors as String

I have a login form. When the submit button is hit, I check via the GraphQL backend if email and password are correct. If yes, a token is returned and stored in local storage. At times, there are errors like:
'Incorrect Password' or 'User Doesn't Exist'.
Is there any way to store these errors as strings so I can display them later using conditional rendering?
This is how my mutation looks like:
function submitForm(LoginMutation: any) {
const { email, password } = state;
if(email && password){
LoginMutation({
variables: {
email: email,
password: password,
},
}).then(({ data }: any) => {
localStorage.setItem('token', data.loginEmail.accessToken);
})
.catch(console.log)
}
}
and I am using it like this in my return
return (
<Mutation mutation={LoginMutation}>
{(LoginMutation: any) => (
....)}>
</Mutation>
)
For now, I am just displaying a single error on the basis of whether the token exists or not but I want to make my error specific to the GraphQL errors.
function ShowError(){
if (!localStorage.getItem('token'))
{
console.log('Login Not Successful');
return <Typography color='primary'>Login Not Successful</Typography>
}
}
Edit:
Example Error:
[Log] Error: GraphQL error: Key (email)=(c#c.com) already exists.
I tried this but it never logs anything:
.then(({data, errors}:any) => {
if (errors && errors.length) {
console.log('Errors', errors);
setErrorMessage(errors[0].message);
console.log('Whats the error', errors[0].message)
} else {
console.log('ID: ', data.createUser.id);
}
})
```
The backend isn't made by me
It depends on how you have a few things set up, but, assuming you have access to state in your ShowError function:
When using GraphQL, errors can happen in 2 ways:
1. A network error, which will be caught in the .catch. To handle this, in your catch you can store the error message in state, and then access it from ShowError:
...
.catch(err => {
setState({errorMessage: err.message});
});
As a result of a bad query, which generally returns a successful response with an errors array. To handle this case, you can add an error check in your .then:
...
.then(({data, errors}) => {
if (errors && errors.length) {
setState({errorMessage: errors[0].message});
} else {
localStorage.setItem('token', data.loginEmail.accessToken);
}
});

What's the best way to deal with an error in the server side and in the client side using nodejs + express

I'd like to know the best way to deal with errors in a response - request.
I have this route that receive a request:
app.get('/getInfo', function (req, res, next) {
let obj = {}
try {
obj = {
...
date: lastUpdatedDate('./utils/appVersion.js'),
...
}
res.status(200).send(obj)
} catch (error) {
console.log(error.message)
res.send({error: "The data wasn't load"})
}
})
And this function where the request is made
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
this.appInfoHandler(resp.data)
})
.catch(function (error) {
console.log(error)
})
}
What's the best way to deal with the error if it occurs in the server side?
Let's supose that in this code block the directory doesn't exists: lastUpdatedDate('./directoreyDoesntExists/appVersion.js'),
So my code goes to the catch block.
Should I send the error like this:
res.send({error: "The data wasn't load"})
Should I set a status like this?
res.status(500).send({error: "The data wasn't load"})
Or should I set a status with a different status code?
Based on that, what's the best way to deal with it in my frontend method getInfo() to get the error and show the error message on web interface?
Should I do an if else inside the .then block like this?
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
if(resp.status === 200){
this.appInfoHandler(resp.data)
}else if (resp.status === 400){
//print error message on web interface
}else if (resp.status === 500){
//print error message on web interface
})
.catch(function (error) {
console.log(error)
})
Or should I deal with this error directly in the catch block like this
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
this.appInfoHandler(resp.data)
})
.catch(function (error) {
//print error message on web interface
})
}
For this case
res.send({error: "The data wasn't load"})
vs
res.status(500).send({error: "The data wasn't load"})
send a status is just more detailed, but both are ok.
check Proper way to set response status and JSON content
For this case, depends on what you need
then(resp => {
if(resp.status === 200){
this.appInfoHandler(resp.data)
}else if (resp.status === 400){
//print error message on web interface
}else if (resp.status === 500){
//print error message on web interface
})
.catch(function (error) {
console.log(error)
})
vs
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
this.appInfoHandler(resp.data)
})
.catch(function (error) {
//print error message on web interface
})
}
You can handle all the errors sending them to the catch block
else if (resp.status === 400){
//print error message on web interface
not printing the error in here but throwing a new error that will be send it to the catch block
throw new ApiError("UserNotFount",400,"not found");
throw new Error('Error 400, not found');
For this case
res.send({error: "The data wasn't load"})
vs
res.status(500).send({error: "The data wasn't load"})
I would suggest sending error as well as status code because that will be more descriptive for the client.
and for the second case
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
if(resp.status === 200){
this.appInfoHandler(resp.data)
}else if (resp.status === 400){
//print error message on web interface
}else if (resp.status === 500){
//print error message on web interface
})
.catch(function (error) {
console.log(error)
})
vs
getInfo () {
axios.get(process.env.REACT_APP_HOST + '/getInfo')
.then(resp => {
this.appInfoHandler(resp.data)
})
.catch(function (error) {
//print error message on web interface
})
}
In this case I would suggest to use the catch block directly whenever you get an error because response status depends on error but not the other way around
As a beginner working on a REST Api, you should take a look at a guidelines - microsoft's are pretty legit: https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design.
Basically, you need to return the correct HTTP code for each request, take a look at https://http.cat/ - for example if the request is malformed, return 400, and if the user is unauthorized return 401:
if (!req.body.name) {
res.status(400).send({ error: 'missing user name' }); // 400 bad request
}
const user = getUser(req.body.name, req.body.pass);
if(!user) {
res.status(401).send({ error: 'user does not exist' }); // 401 unauthorized
}
try {
const token = createToken(user);
// better to set a cookie
res.status(200).send({ token }); // 200 success
} catch(e) {
res.status(500).send({ erroe: e.message }); // 500 internal error
}
if(isTeapot) {
res.status(418).send({ error: 'I can only make tea' }); // 418 teapot, totally real
}
To make things easier there are a lot of libraries to help you generate better error messages and handle errors better, one of my favorites is celebrate
Any status code other that 200 would mean unsuccessful so you dont need to use those if-else statements. The better alternative is to catch the error and send it with response as it is. The benefit is that you would receive the type of error occured without hardcoding the status codes.
(for ex, we take the status code here to be 400 unsuccessful)
.catch(function (error) {
//print error message on web interface
res.status(400).send(JSON.stringify(error, undefined, 2));
});
By using the stringify method you can print the exact error on the console also.
.catch(function (error) {
console.log(JSON.stringify(error, undefined, 2));
});
The parameters in the stringify method here are:
error object
undefined: The array which contains the keys for filtering the keys in the object(here, error). All those keys present in this array are only the ones not filtered out.
2: It is used to introduce whitespace in object representation

How to catch and handle error response 422 with Redux/Axios?

I have an action making a POST request to the server in order to update a user's password, but I'm unable to handle the error in the chained catch block.
return axios({
method: 'post',
data: {
password: currentPassword,
new_password: newPassword
},
url: `path/to/endpoint`
})
.then(response => {
dispatch(PasswordUpdateSuccess(response))
})
.catch(error => {
console.log('ERROR', error)
switch (error.type) {
case 'password_invalid':
dispatch(PasswordUpdateFailure('Incorrect current password'))
break
case 'invalid_attributes':
dispatch(PasswordUpdateFailure('Fields must not be blank'))
break
}
})
When I log the error this is what I see:
When I check the network tab I can see the response body, but for some reason I can't access the values!
Have I unknowingly made a mistake somewhere? Because I'm handling other errors from different request fine, but can't seem to work this one out.
Example
getUserList() {
return axios.get('/users')
.then(response => response.data)
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
}
Check the error object for response, it will include the object you're looking for so you can do error.response.status
https://github.com/mzabriskie/axios#handling-errors
Axios is probably parsing the response. I access the error like this in my code:
axios({
method: 'post',
responseType: 'json',
url: `${SERVER_URL}/token`,
data: {
idToken,
userEmail
}
})
.then(response => {
dispatch(something(response));
})
.catch(error => {
dispatch({ type: AUTH_FAILED });
dispatch({ type: ERROR, payload: error.data.error.message });
});
From the docs:
The response for a request contains the following information.
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the server response
status: 200,
// `statusText` is the HTTP status message from the server response
statusText: 'OK',
// `headers` the headers that the server responded with
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {}
}
So the catch(error => ) is actually just catch(response => )
EDIT:
I still dont understand why logging the error returns that stack message. I tried logging it like this. And then you can actually see that it is an object.
console.log('errorType', typeof error);
console.log('error', Object.assign({}, error));
EDIT2:
After some more looking around this is what you are trying to print. Which is a Javascipt error object. Axios then enhances this error with the config, code and reponse like this.
console.log('error', error);
console.log('errorType', typeof error);
console.log('error', Object.assign({}, error));
console.log('getOwnPropertyNames', Object.getOwnPropertyNames(error));
console.log('stackProperty', Object.getOwnPropertyDescriptor(error, 'stack'));
console.log('messageProperty', Object.getOwnPropertyDescriptor(error, 'message'));
console.log('stackEnumerable', error.propertyIsEnumerable('stack'));
console.log('messageEnumerable', error.propertyIsEnumerable('message'));
Here is the proper way to handle the error object:
axios.put(this.apiBaseEndpoint + '/' + id, input)
.then((response) => {
// Success
})
.catch((error) => {
// Error
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
// console.log(error.response.data);
// console.log(error.response.status);
// console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
Origin url https://gist.github.com/fgilio/230ccd514e9381fafa51608fcf137253
axios.post('http://localhost:8000/api/auth/register', {
username : 'test'
}).then(result => {
console.log(result.data)
}).catch(err => {
console.log(err.response.data)
})
add in catch
geting error response ==> err.response.data
I was also stumped on this for a while. I won't rehash things too much, but I thought it would be helpful to others to add my 2 cents.
The error in the code above is of type Error. What happens is the toString method is called on the error object because you are trying to print something to the console. This is implicit, a result of writing to the console. If you look at the code of toString on the error object.
Error.prototype.toString = function() {
'use strict';
var obj = Object(this);
if (obj !== this) {
throw new TypeError();
}
var name = this.name;
name = (name === undefined) ? 'Error' : String(name);
var msg = this.message;
msg = (msg === undefined) ? '' : String(msg);
if (name === '') {
return msg;
}
if (msg === '') {
return name;
}
return name + ': ' + msg;
};
So you can see above it uses the internals to build up the string to output to the console.
There are great docs on this on mozilla.
The only thing what helped me was the following:
axios.put('/api/settings', settings, {
validateStatus: status => status >= 200 && status < 300 || status === 422
})
https://stackoverflow.com/a/66285529/5849569
You can use inline if else statement like so:
.catch(error => {
dispatch({
type: authActions.AUTH_PROCESS_ERROR,
error: error.response ? error.response.data.code.toString() : 'Something went wrong, please try again.'
});
});
I recommend handling errors via Axios interceptors, individually for each case scenario:
// interceptor to catch errors
const errorInterceptor = (error) => {
// check if it's a server error
if (!error.response) {
console.log('📡 API | Network/Server error')
return Promise.reject(error)
}
// all the error responses
switch (error.response.status) {
case 400:
console.error(error.response.status, error.message)
console.log('📡 API | Nothing to display', 'Data Not Found')
break
case 401: // authentication error, logout the user
console.log('📡 API | Please login again', 'Session Expired')
localStorage.removeItem('user')
break
case 403:
console.error(error.response.status, error.message)
console.log('📡 API | Access denied', 'Data Not Found')
break
case 404:
console.error(error.response.status, error.message)
console.log('📡 API | Dataset not found', 'Data Not Found')
break
case 422:
console.error(error.response.status, error.message, error.response.data.detail)
console.log('📡 API | Validation error', 'Unprocessable Content')
break
default:
console.error(error.response.status, error.message)
}
return Promise.reject(error)
}

Categories

Resources