I want to take a specific action when an API request results in a 404 error. I've read that the appropriated way to do this would be handling the error in the application adapter like below:
handleResponse: function(status, headers, payload){
if(status === 404 && payload.errors){
//handle error
}
return this._super(...arguments);
}
The problem is, as soon as I set up the adapter, it won't finish loading the page so I can handle the error on the page itself. Instead, it automatically takes me to some error route that just says "Adapter error". How can I stop/override this behaviour?
Turns out I needed to adjust the handleResponse hook in the application adapter to pass the new requestData parameter to the super method.
handleResponse (status, headers, payload, requestData) {
return this._super(status, headers, payload, requestData);
},
Then I just changed the first line of the code in my question from
handleResponse: function(status, headers, payload) {
to
handleResponse: function(status, headers, payload, requestData) {
I was then able to catch and handle the error
Perhaps you could handle it on a request basis like below:
return this.get('store').find('user', userId).then((user) => {
this.set('user', user);
}).catch((reason) => {
var possible404 = reason.errors.filterBy('status','404');
if(possible404.length !== 0) {
// Handle 404 error
}
});
Although this is not the solution that you wanted, this alternative will allow you to customize more. By the way, the automatic behavior seems to be the application-error substates kicking in on 404, so give it a read if you want to override the behavior.
Related
At this moment i'm using a response interceptor instance.interceptors.response.use for global error handling. In that function i'm redirecting in case of a 404, i'm clearing the storage in case of a 401 etc. Which works fine :)
Except now I've got a spot where i want to handle the 404 error differently, but a simple try/catch or a .catch won't work since the axios interceptor intercepts the response and redirects immediately.
Whats the best practice in this situation?
Not using the interceptor for global error handling? (but then what? call a handleError kind of function after every request except this one?)
Temporary turn it off somehow
Pass an ignore404 option or something with the axios request (although I use a function per request so i can't do this really simple)
What would be the best, but i'm not sure how is that axios is always doing some global error reporting except when you catch it yourself. And at that point at the bottom of the catch i could let the global error handler do it's job anyway if i want to
My interceptor:
function onResponseRejected(error) {
const { response } = error;
if (!response) return Promise.reject(error); // network error, not axios related
const { status } = response;
const { errors } = response.data;
if (status === 403) {
router.push({ name: '403' });
} else if (status === 404) {
router.push({ name: '404' });
}
....
....
My axios requests
export const fetch = (some) => {
return get(`some/${someId}/url/`)
}
My application usage of a request
const response = fetch(this.$route.params.connectorId, this.$route.params.mapperId).catch(() => {
console.log('At this moment the request will be redirected to another route...');
});
I have a http service that handles http requests. It has a handler that treats errors by popping up a modal on the screen.
I also have an interceptor that catches requests to insert an authorization token in case they need one. The token is taken from requesting another service.
The problem is, if the authorization request is needed and it fails, the modal error is shown twice even if the second request is never sent.
If think there's something wrong in the way I'm dealing with the Observable stream. Could someone help please?
/// http service
request(url, body, headers) {
return this.httpClient.post(url, body, headers).pipe(
catchError(() => this.handleError())
);
}
handleError() {
this.showModal();
return throwError('Theres been an error.');
}
/// interceptor
intercept(request, next) {
const authorization = request.headers.get('Authorization');
if (authorization) {
return this.httpService.request(url, body, headers).pipe(
exhaustMap(token => {
const newRequest = request.clone({
headers: request.headers.set(
'Authorization',
token
)
});
return next.handle(newRequest);
})
);
}
return next.handle(request);
}
Have you tried to console.log out the errors you're getting. It is possible that you're getting two differents errors.
Are you sure about this part of the code as well:
const newRequest = request.clone({
headers: request.headers.set(
'Authorization',
token
)
});
In some libraries setting headers after a request is sent is not permitted.
I am using isomorphic-fetch to perform AJAX requests from my react-redux application. In my api middleware I have the following function which calls the external resource:
import fetch from 'isomorphic-fetch';
function callApi({ endpoint, method, body, params = {} }) {
let route = generateRoute(endpoint, params);
return fetch(route, generateFetchOptions(method, body))
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
return response.json();
});
}
The above function is called by the following piece of code:
return callApi(callAPI).then(
response => next(actionWith({
response,
type: successType,
statusCode: 200
})),
error => error.json().then(errorObject => {
return next(actionWith({
type: failureType,
statusCode: errorObject.statusCode,
error: errorObject.message || 'Something bad happened'
}));
})
);
If I reject with Promise.reject(response) the error is being handled by the error handler, but for some reason the error also bubbles to the browser console (in my case Chrome).
Here is a screenshot from the console which shows what is happening (api.js:34 is the second line of the callApi method):
This is the usual behavior (in probably every browser?) when hitting an error during an HTTP request (no matter whether a linked image cannot be found, or an XHR fails). No matter if and how you handle those errors, they will always be logged to the console. There is no way to suppress this behavior.
References:
Provide a way not to display 404 XHR errors in console
How can I stop jQuery.ajax() from logging failures to the console?
I am having issues trying to gracefully handle $http errors. I am looping over a list of servers to make API calls to for status. The calls that complete successfully for perfectly. The ones that fail are not giving me access to the error information. It is always undefined. Here is the code snippet:
angular.forEach($scope.servers, function (server) {
// blank out results first
server.statusResults = {};
$http.jsonp(server.url + '/api/system/status?callback=JSON_CALLBACK', {headers: { 'APP-API-Key': server.apiKey }}).
success(function (data, status, headers, config) {
server.statusResults = data;
}).
error(function (data, status, headers, config) {
// data is always undefined here when there is an error
console.error('Error fetching feed:', data);
});
}
);
The console output shows the correct 401 error (which I didn't output) and my console error message (which I did output) with an undefined data object.
GET https://server_address/api/system/status?callback=angular.callbacks._1 401 (Unauthorized) angular.min.js:104
Error fetching feed: undefined
What I am trying to do is NOT have Angular display the 401 in the log, and instead I will display it in a graceful way. However since data is undefined I have no way of accessing the information.
I am new to AngularJS, but my example closely matches other examples I've found in the documentation.
I've also tried using $resource instead of the $http and got the exact same problem.
var statusResource = $resource(server.url + '/api/system/status', {alt: 'json', callback: 'JSON_CALLBACK'},
{ status: {method: 'JSONP'}, isArray: false, headers: { 'APP-API-Key': server.apiKey } });
// make status API call
statusResource.status({}, function (data) {
server.statusResults = data;
}, function (err) {
// data is always undefined here when there is an error
console.log(err);
});
I'm probably doing something obviously wrong, but I'm not sure what else to try.
Per the $http docs, body is
The response body transformed with the transform functions.
With the 401 (Unauthorized) error you are getting back, it is quite possible there is no body being returned, hence why it is undefined.
If you want to log the error code, log the status parameter instead. It contains the HTTP Status Code, which should be uniform, unlike response bodies.
I have a basic CRUD application up and running, however what I am wanting to do is wrap every response from the server with two additonal parameters namely
'error' => boolean, 'errorMessage' => string, 'data' => {whatever data}
so that I can handle when a successful request is sent and returned from the server, however the database was unable to update for some reason so I can not only keep the UI in sync with the DB, but also present the user an error message on a failed update.
As AngularJS expects an updated object the UI will be in sync if I return the same object on failure, but as there would be no notification of failure the user wouldn't realize what the problem is.
Within my old applications pre-Angular (jQuery based) I could easily decode the json data on every response and if error === true present an error message, but in Angular I cannot seem to figure out how to accomplish this.
I may very well be off base here as I am just getting into Angular so any direction would be helpful.
Make this http request from angularjs and send back a response object from server.
response object --->{'error' => boolean, 'errorMessage' => string, 'data' => {whatever data}}
which gets collected in Resdata. use Resdata to take action.
$http({method: 'POST', url:url, data:body}).success(function(Resdata, status, headers, config) {
console.log(Resdata);
if(Resdata.error == true){
// use Resdata.errorMessage
}
else if(Resdata.error == false){
// use Resdata.data
}
}).error(function(Resdata, status, headers, config) {
console.log("error:", error);
});