Angular 5 HttpClient Error response not catchable - javascript

We're working with Angular 5 and a Spring 2 OAuth Backend.
Now when I send an old token it's of course expired. It returns status code: 401 and an error response with invalid token and so on. Now I can't see it in my logs or when I catch the error. I want to get the error so I can at first log it and later on either refresh the token or send him to the Login Page.
Now if i subscribe to the request with:
.subscribe(res => {
//just random stuff.
}, err => {
console.log("error", err);
});
I just see this response in the log with an unknown error like in this image
Could it be failure of the backend? Because i also see in the logs something like a "No 'Access-Control-Allow-Origin' header is present"-error, although it's because of the invalid token.
Although I can see this response code in Google Chrome Dev Tools
and a 401 status code.
So I tried to find a solution myself. I've already got an interceptor and tried it with some solutions
return next.handle(authReq)
.catch(error => {
console.log("im in here");
console.log(error);
return Observable.throw(error);
});
The Http Service just throws an error that catch is not a function without even logging the error or the "im in here".
I have also tried with the .do after next.handle and I got the same error like catch
.do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff with response if you want
}
}, (err: any) => {
console.log(err);
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
}
}
});
I've tried with pipe after the http.get but it doesn't work either.
http.get(...).pipe(
retry(3), // retry a failed request up to 3 times
catchError(this.handleError) // then handle the error
);

import 'rxjs/add/operator/catch';
Somefunc(){
this.httpClient
.get("data-url")
.subscribe(
data => console.log('success', data),
error => console.log('oops', error)
);
}
OR
this.httpClient
.get("data-url")
.catch((err: HttpErrorResponse) => {
// simple logging, but you can do a lot more, see below
console.error('An error occurred:', err.error);
});
Should work.

Related

Angular catching "standard" errors instead of my API's errors

I have a service that looks like this:
return this.http
.post(requestUrl, body, { headers, observe: 'response' })
.toPromise()
.then((res: any) => {
return res.body?.data || res?.body?.message;
}).catch((err) => {
console.log('error', err);
})
When i trigger an error, this is what i get on the console.log:
error Error Code: 400
Message: Http failure response for <MY API ENDPOINT>: 400 OK
But on the network tab (Google chrome dev tools) i see this:
{
"message": "Unsupported value, please contact support.",
"status": "failure"
}
How can i read my message that i'm sending from my Backend in my angular .catch block?

Trying to access error response 500 axios

I am not able to access the response of error - 500 in axios
export const dowloadFilePDF = (data) => {
return axios
.request({
method: 'GET',
url: `${basePath + data[0]}`,
responseType: 'blob',
headers: { Authorization: Authorization },
})
.then(response => {
console.log(response)
let fileName = response.headers['content-disposition']?.split(';')[1]?.split('=')[1]?.split('"').join('')
fileName = fileName ? fileName : 'data.pdf'
fileDownload(response.data, fileName)
})
.catch((error) => {
console.log(error.response.data)
})
}
I am not getting the response instead its returning as
data : Blob {size: 215, type: 'application/json'}
According to the documentation, you can't assume error.response will be filled in. Here's the code the documentation shows with the inline comments explaining it:
Handling Errors
axios.get('/user/12345')
.catch(function (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);
});
There's another aspect to this as well: You're calling catch on the promise returned by then, not on the promise returned by axios. If the axios promise is rejected, you'll reach that rejection handler, but you'll also reach it if the axios promise is fulfilled but then your fulfillment handler throws an error (or returns a promise it ultimately rejects). In that latter case, the error probably won't have a response property at all.
the best way to catch errors instead of trying a lot of lines of code in the catch method by promise is using the tools in the Axios names interceptor.
interceptor has two property request and response. In response we can simulate the errors status and based on the status code we can do whatever we want. for example :
axios.interceptors.response.use(null, error => {
console.log("error : " , error);
const expectedError = error.response && error.response.status >= 400 &&
error.response.status < 500;
if (expectedError) {
return Promise.reject(error);
}
alert("unexpected error is happen");
});
if you need more help here is the original link

I'm getting "Uncaught (in promise) TypeError: Cannot read property 'data' of undefined" error in axios patch api

I am trying to update an array of objects using an Axios/Node.js API. I have successfully created the array, but when I try to pass in through an axios patch request, I am getting the "Cannot read property 'data' of undefined". Anyone know what I might be doing wrong?
My axios function is below:
export const updateTrans = async (transArr) => {
try {
const res = await axios({
method: 'PATCH',
url: `http://127.0.0.1:7000/api/v1/property/${id}`,
data: {
"transactions": transArr }
});
if (res.data.status === 'success') {
showAlert('success', 'Data updated successfully!');
}
} catch (err) {
console.log(err.response.data.message );
showAlert('error', err.response.data.message);
}
};
I have tried to stringify "transArr" as well, but still no luck.
The problem is that you're accessing err.response.data without checking if err.response exists. err.response is only present if the request was made and there was a response. If, for example, a CORS error or some network error occurred (or some other error inside the try block), it will not be present.
Just check that err.response exists before using it.
try {
// ...
} catch (err) {
console.log(err, err.response && err.response.data);
if (err.response && err.response.data) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
showAlert("error", err.response.data.message);
return;
}
showAlert("error", err.message);
}

Axios post entering catch block even after successful Rest API call completion

My axios post request is not returning the value returned by the API in a non success 401 scenario. It works fine when its a success scenario.
My reset Password API returns the status code, and a message for every call. when I use post man to test its output for resetting a password, giving incorrect current password, I get
Postman Output:
statusCode: 401,
headers: {
.......
........
},
body: "{"code":"NotAuthorizedException","name":"NotAuthorizedException","message":"Incorrect username or password."}" <--- This is the body output
But in my axios post, it goes to the catch block:
await Axios.post(resetAPIUrl, resetParams, config).then(value=> {
console.log(`Returned data ----> ${JSON.stringify(value)}`);
resolve(value);
}).catch(error=>{
console.log(`Failing--->${error}`)
reject(error)
});
this is the error that I am getting in the catch block of Axios post:
Error: Request failed with status code 401
The error reason is correct. But why isn it going into catch block? Its a successful completion of the process. Calling the API directly from post man gives me the correct output structure.
Interceptor was the answer. Since Axios doesn't consider any response other than 200 as the success scenario, interceptors can be used to capture the other responses:
{
Axios.interceptors.request.use(req=>{
console.log(`This is the request ---> ${req.method} ${req.url}`)
return req;
})
Axios.interceptors.response.use(res => {
console.log(`res status ---> ${res.status}`)
resolve(res)
return res;
}, (error)=>{
console.log(`This is the error status ---> ${error.response.status}`)
if(error.response.status === 401){
resolve(error.response);
}
})
await Axios.post(resetAPIUrl, resetParams, config);

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

Categories

Resources