How to use interceptors to handle response globally - javascript

I have just started exploring axios and using interceptors
In my code, I have axios api call here and there, So I used interceptors to handle error,
but it still show uncaught error in my console. I dont know why is that?
For example, this is my api code:
export const getcountryAllocations = async (country: string) => {
const response = await instance.get<IcountryAllocationTypeResponse[]>(
`/asa/${country}`
)
return response.data
}
So, in order to handle error in a centralized way, I used interceptors to handle error.
export const instance = axios.create()
instance.interceptors.response.use(
res => {
return res
},
error => {
if (error.response.status === 401) {
console.log(error)
}
throw error
}
)
But I still get a red error in console when I get api request error, say the example api I mentioned above
GET http://localhost:30087/asa/USD 401 (Unauthorized)
AxiosError {message: 'Request failed with status code 401', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
localhost/:1 Uncaught (in promise) AxiosError {message: 'Request failed with status code 401', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
But I expect that it shouldnt display localhost/:1 Uncaught anymore, as I have handled it in interceptors

You are catching the error but then throwing it again. That's why you still have the red error in the console.
What you can do is catch the error and then return an object saying an error occurred without throwing it again.
export const instance = axios.create()
instance.interceptors.response.use(
res => {
return res
},
error => {
if (error.response.status === 401) {
console.log(error)
}
return {
success: false,
message: error.message,
status: error.response.status
}
}
)

Related

Axios error status code UnhandledPromiseRejectionWarning

Using axios, I'm making GET requests to multiple links to test to see if they are broken links. If the GET requests returns an error, I want to log this error to the console and send it to the client side with socket. However, on some links (not all), I get an UnhandledPromiseRejectionWarning.
// check if the link is dead
axios.get(linkHref, {
auth: {
username: USERNAME,
password: PASSWORD
}
})
.then( (response) => {
if (response.status != 200) {
resultData = {
text: linkText,
url: linkHref,
statusCode: String(response.status)
}
console.log(resultData);
io.sockets.emit("result", resultData); // send link to client-side
}
})
.catch( (error) => {
if (error) {
resultData = {
text: linkText,
url: linkHref,
statusCode: String(error.response.status) // this is where the error is
}
console.log(resultData);
io.sockets.emit("result", resultData); // send link to client-side
}
});
I expect it work correctly and return the status code of the error but sometimes I get a UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'status' of undefined error. But with my if statement in the .catch, I am checking to make sure that there is an error and that it is not undefined so I don't understand why I'm getting this error.
EDIT: Also, this works (does not show me that error) when I run it on my Mac but not in Windows ... why?
TypeError: Cannot read property 'status' of undefined The response property on error.response is not defined eg error = { response: undefined }. Therefore, referencing any properties on it throws an error. error.response[property]
Also on failed/hanging http requests the error argument is different. Checkout this gist axios-catch-error. The error argument will have different properties for this case.
hey can you check by validating whether you are getting the response property on the error object in the if else condition
.catch( (error) => {
if (error.response) {
//rest of the code...
}
});

How to handle empty json responses from server

I have a function in my front end app which calls my node.js backend server:
Client function:
this.geocode = (placeName) => {
const url = '/api/twitter/geocode?' + 'query=' + encodeURIComponent(placeName);
return fetch(url)
.then(processResponse)
.catch(handleError)
}
// API Helper methods
const processResponse = function (response) {
if (response.ok) {
console.log(response);
return response.json()
}
throw response;
}
const handleError = function (error) {
if (error.json) {
error.json().then(error => {
console.error('API Error:', error.message || error)
})
} else {
console.error('API Error:', error.message || error)
}
}
Server route:
app.get('/api/twitter/geocode', (req, res) => {
var parameters = {
query: req.query.query
}
Twitter.get('geo/search', parameters)
.then(response => {
console.log("RESPONSE:")
console.log(response);
// check if there is a place for the given query
if(response.date.places.length > 0){
res.send(response.data.result.places[0].bounding_box.coordinates[0][0]);
}
res.send()
})
.catch(e => res.status(500).send('Something broke!')
)
});
There is a problem when placeName is the name of a place that doesn't exist (or at least that Twitter doesn't know about). The console.log(response) in the backend shows me that such a request to the Twitter api leads to a return message without place data:
{ data:
{ result: { places: [] },
query:
{ url: 'https://api.twitter.com/1.1/geo/search.json?query=FOOBARTOWN',
type: 'search',
params: [Object] } },
resp:
/*etc...*/
As you can see, places is an empty list. This response causes a crash in my frontend. I would like to know why. Look at the error message:
const handleError = function (error) {
if (error.json) {
> error.json().then(error => {
console.error('API Error:', error.message || error)
})
} else {
And some other console outputs in the browser:
GET http://localhost:3000/api/twitter/geocode?query=FOOBARTOWN 500 (Internal Server Error) (model.js:197)
Uncaught (in promise) SyntaxError: Unexpected token S in JSON at position 0
at handleError (model.js:214)
It seems like we are getting error 500. But why? My server hasn't failed. There's no error message in the node.js console.
Also, it seems like the program ends up in handleError, and then fails to convert the error to json.
Why does it go to handleError? What's the error?
Why does it say my server failed (error 500)?
How can I make sure that if this.geocode gets an empty message, I don't crash, and return that empty message (so I can check for an empty message and act appropriately in my React.js component)?
Why does it go to handleError? What's the error?
Your server is sending a 500 status code, with Something broke! as response body.
An when you try to use res.json() on a non JSON string you get:
Uncaught SyntaxError: Unexpected token S in JSON at position 0
The line if(error.json) is not doing what you think it does. handleError is being called when response.ok is false, since you're throwing the fetch response object otherwise, in that case error argument will be a fetch response that implements Body, which has a json method, even if the body isn't a JSON, which is your case.
Your handleError can be written like this, where you will handle fetch errors and non 2xx responses.
const handleError = async function(error) {
if(error instanceof Response) {
if(error.headers.get('content-type').includes('application/json'))
error = await error.json();
else error = await error.text();
}
console.error('API Error:', error.message || error)
}
Why does it say my server failed (error 500)?
Place a console.log(e) on Twitter.get().catch and you'll find out.
Your Twitter.get().then is also wrong, since you're sending the response twice.
if(response.date.places.length > 0){
res.send(response.data.result.places[0].bounding_box.coordinates[0][0]);
}
res.send()
Should be:
if(response.date.places.length > 0)
return res.send(response/*...*/);
res.send()

How to detect a 401 with axios and stop the console error

I am trying to use axios to call an API and return data.
I have the following code which works fine
axios.get('http://api/courses')
.catch(function (error) {
if (error.response) {
console.log(error.response.status);
} else {
console.log('Error', error.message);
}
})
.then(response => {
console.log(response.data)
});
This works fine, the API returns a 200 and data so in the console I get the data returned.
However this does not work
axios.get('http://api/courses')
.catch(function (error) {
if (error.response) {
console.log(error.response.status);
} else {
console.log('Error', error.message);
}
})
.then(response => {
console.log(response.data)
});
On the above call i get a 401 returned from the API, I want to be able to detect that and do something (where i am currently doing a console.log). However in the console I get the following errors:
GET http://api/courses 401 (Unauthorized)
(anonymous) # spread.js:25
e.exports # spread.js:25
e.exports # spread.js:25
Promise.then (async)
r.request # spread.js:25
r.(anonymous function) # spread.js:25
(anonymous) # index.js:20
(anonymous) # (index):49
(index):58 Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at axios.get.catch.then.response ((index):58)
at <anonymous>
Is there a way to capture a 401? It seems like common practice by API's that require auth, but I cannot seem to work it out.
Thanks
You can add an interceptor that will catch all 401 responses. That way you can fire a redirect or any sort of actions you might need. In this example I am dispatching a redux action that will clean up some user data and render the login form.
const UNAUTHORIZED = 401;
axios.interceptors.response.use(
response => response,
error => {
const {status} = error.response;
if (status === UNAUTHORIZED) {
dispatch(userSignOut());
}
return Promise.reject(error);
}
);
For me (with axios 0.19) both work:
axios.interceptors.response.use(response => response, error => {
if(error.response.status === 401) store.dispatch(logout);
return error;
});
and
axios.interceptors.response.use(response => {
if(response.status === 401) store.dispatch(logout);
return response;
});
I'm adding this because I've saw both versions in different sources and also Neil told that the version that uses the error handler to intercept didn't work for them, so may be another one is helpful to somebody too.
Added debugger to check the object, so this is how the error object looks like.
Refer screenshot. Right side(under scope)
It very easy to catch and handle 401 through the error.response.
error => {
if (err.response.status) {
props.navigation.navigate('Login');
return;
}
});

redux-saga catch Failed to load resource: net::ERR_CONNECTION_REFUSED

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
};
}

Possible Unhandled Promise Rejection - React-Native with Firebase

I am trying to make a fetch API call to a new Firebase instance with my React-Native app, but I am running into this error:
Possible Unhandled Promise Rejection (id: 0):
Network request failed
TypeError: Network request failed
at XMLHttpRequest.xhr.onerror (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:25119:8)
at XMLHttpRequest.dispatchEvent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:10405:15)
at XMLHttpRequest.setReadyState (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:26688:6)
at XMLHttpRequest.__didCompleteResponse (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:26536:6)
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:26630:52
at RCTDeviceEventEmitter.emit (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:9638:23)
at MessageQueue.__callFunction (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7493:34)
at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7375:8
at guard (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7306:1)
at MessageQueue.callFunctionReturnFlushedQueue (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false:7374:1)
The functions look like so:
getNotes(username){
username = username.toLowerCase().trim();
var url = `https://myproject-6342.firebaseio.com/${username}.json`;
return fetch(url).then((res) => res.json());
},
addNote(username, note){
username = username.toLowerCase().trim();
var url = `https://myproject-6342.firebaseio.com/${username}.json`;
return fetch(url, {
method: 'post',
body: JSON.stringify(note)
}).then((res) => res.json());
}
What is going wrong here?
The promise from the fetch API will reject with a TypeError when a network error occurs, which means you have to handle the error. Example:
function _handleError(errorMessage) {
console.log(errorMessage);
}
fetch('https://api.github.com/users/octocat/repos').then(function(response) {
if(response.ok) {
return response.json();
} else {
_handleError(`Oops, something went wrong: ${response.status}, ${response.statusText}`);
}
}).then(function(data) {
if(data) {
console.log('success', data);
}
}).catch(function(error) {
_handleError(`There has been a problem with your fetch operation: ${error.message}`);
});
More info here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
Well in my case the emulator internet was not working, I followed the below thread to make that work.
Android emulator not able to access the internet

Categories