Cannot .catch() an error when using Jquery.ajax().then() - javascript

I am hitting a number of API's from JQuery, and caching the result of each so that the data can be re-used multiple times in the page to render some dashboard widgets in different formats.
The problem is that if an API returns a 500 status code with error, I don't want to try and draw the widget, but capture the error in a friendly way.
However, I cannot figure out how .catch works with the JQuery.ajax() function. After reading here, here, here, here and a dozen others, I've got so far but always get the same console error:
TypeError: LoadDataFromApi(...).then(...).catch is not a function
I've tried to comment the code to explain what I'm trying to do at each stage. Please somebody explain why the whole .catch thing isn't working for me.
// Cache object to save API data for re-use
var requestCache = {};
// Get API data and save to cache
function LoadDataFromApi(apiUrl) {
if (!requestCache[apiUrl]) {
var result = $.ajax({
type: 'GET',
url: apiUrl,
dataType: "json",
statusCode: {
500: function (xhr) {
var err = JSON.parse(xhr.responseText);
console.log('Message:' + err.Message);
// throw err.Message; // removed because this was always an "uncaught exception", even if used within try/catch
},
200: function (xhr) {
// Do nothing here - put result into cache regardless of status code
}
}
});
requestCache[apiUrl] = result; // save the JSON data into cache
}
return requestCache[apiUrl];
}
// Called by page on load
function LoadJsonData() {
LoadDataFromApi('/api/GetFoo?Row=10')
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
LoadDataFromApi('/api/GetFoo?Row=10') // this returns cached data because API has already been hit
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
LoadDataFromApi('/api/GetBar')
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
}

Use .fail() as described in your first link here
Depending on your jQ version
"Deprecation Notice: The jqXHR.success(), jqXHR.error(), and
jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use
jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead."
EDIT:
You error callback should accept 3 arguments, so make it so
function(jqXHR,textStatus,errorThrown ){}

JQuery does not return typical promise, it's$.Deferred in that case:
http://api.jquery.com/jquery.ajax/
http://api.jquery.com/category/deferred-object/
More on that here, with answers:
Deferred versus promise

Related

javascript observable error handling

I am trying to generate custom error handling when my observable fails instead of getting a big 404 error in my console. However, no matter how many tutorials I read I jsut can't figure out how it works.
my code is as follows:
datacontext.graph.getUserProfilePicture('', detailedData.id)
.then(function success(photo) {
console.log("succesful call" + photo);
})
.catch(function error(err) {
console.log("error" + err);
});
The success statement works, however the fail method doesn't.
Here is the call that I make to the ,icrosoft graph endpoint:
function getUserPic(principalName) {
var deferred = $q.defer();
var endpoint = config.baseGraphApiUrl + "users/" + principalName + "/photo/$value";
$http.get(endpoint, { responseType: 'blob' }).then(function (result) {
var file = new Blob([result.data], { type: 'image/jpeg' });
var fileURL = URL.createObjectURL(file);
deferred.resolve(fileURL);
}, function (data) {
console.log(error);
});
return deferred.promise;
}
on success it returns:
succesful call blob:http://localhost:8480/7da29a36-d13d-440f-8207-75f1cde58fcf
on failure it returns:
https://graph.microsoft.com/v1.0/users/63c31121-cd15-4f48-ba43-8dea613f19cd/photo/$value 404 (Not Found)
Have you tried this:
.then(function success(photo) {
console.log("succesful call" + photo);
}, function(err){
console.log("error" + err);
})
?
The success statement works, however the fail method doesn't.
.getUserProfilePicture returns a promise. A promise either succeeds (resolved) or fails (rejected). If getUserProfilePicture resolves even by passing invalid data then it has bugs. Your posted code has no problem regarding handling promises' different states.
If you want to reject the promise manually you can throw an error in your success handler:
datacontext.graph.getUserProfilePicture('', detailedData.id)
.then(function success(photo) {
console.log("succesful call" + photo);
throw new Error('I am an error!');
})
.catch(function error(err) {
console.log("error" + err);
});

Multiple post requests in the same method in Angular

$scope.observer_vel_data = function(){
$scope.showOverlay('loadRefPubVel');
$http({
//First http post request
method:'POST',
url:'/api/observer_vel_data',
data:$scope.payload_array,
}).then(function successCallback(response){
console.log('API Endpoint: vel data success!');
//Second post request is made in the method call below
$scope.sentiment_var = $scope.observer_send_sentiment();
$scope.vel_var = response.data.velocity1;
}, function errorCallback(response){
// console.log(response);
$scope.addAlert({
type: 'danger',
msg: 'API call failed'
});
}).finally(function(){
console.log("hello");
console.log($scope.sentiment_var);
//graph is rendered
$scope.update_velocity($scope.vel_var,$scope.sentiment_var);
$scope.hideOverlay('loadRefPubVel');
});
};
So I am trying to render a graph which uses data from two different and independent post requests. However, the graph command is called before the data from the second post request arrives. How can I fix this ? The commands which make the post requests and render the graph are mentioned as comments in the code posted.
$scope.observer_send_sentiment = function (){
// $scope.showOverlay('loadRefSentiment');
var data = {
"angularGroups":$scope.groups
};
// console.log(data);
$http({
method:'POST',
url:'http://localhost:9612/sentiment_velocity',
data:data
}).then(function successCallback(response){
var data = response.data;
var json_obj = JSON.parse(data.replace(/\'/g,'"'));
var sentiments = json_obj["sentiments"];
// console.log(sentiments);
$scope.update_sentiment(sentiments);
console.log(sentiments);
return sentiments;
}, function errorCallback(response){
var errmsg = response.statusText;
console.log(response);
$scope.addAlert({
type: 'danger',
msg: 'API call failed (sentiment basic)' + errmsg,
});
}).finally(function(){
// $scope.hideOverlay('loadRefSentiment');
});
};
If I understand correctly, you want the code in finally(...) execute only after the second request ends.
To enforce that, you need to chain the HTTP request promises, meaning you need to return the promise of the second HTTP request from the success handler of the first request. Your code should look like more or less like this:
$scope.observer_vel_data = function(){
$scope.showOverlay('loadRefPubVel');
$http({
method:'POST',
url:'/api/observer_vel_data',
data:$scope.payload_array,
}).then(function successCallback(response){
console.log('API Endpoint: vel data success!');
$scope.vel_var = response.data.velocity1;
return $scope.observer_send_sentiment();
}).catch(function errorCallback(response) {
//This catch will handle errors from both HTTP requests
$scope.addAlert({
type: 'danger',
msg: 'API call failed'
});
})
.finally(function(){
console.log("hello");
console.log($scope.sentiment_var);
//graph is rendered
$scope.update_velocity($scope.vel_var,$scope.sentiment_var);
$scope.hideOverlay('loadRefPubVel');
});
};
$scope.observer_send_sentiment = function() {
return $http({...}).then(function(response) {
//process the response
...
$scope.sentiment_var = parsedResponseData;
});
};
Note that the finally callback will always execute, regardless of whether an error occured or not. If you want some of it to execute only if an error was not encountered, add another .then(function() {...}) instead.
EDIT: Now that we can that see what observer_send_sentiment does, it might make sense for you to stick to the .then(function successCallback() {...}, function errorCallback() {...}) syntax, and keep separate error callbacks for each of the requests. Just keep in mind that if you ever add another then block and you want errors along the promise chain to prevent executing further .then(function() {...}) blocks, you should add return $q.reject(response) at the end of both errorCallbacks. Not using q.reject from within error callbacks with the .then(function successCallback() {...}, function errorCallback() {...}) syntax renders the promise resolved, not rejected.

How to get error from http service

I am trying to get http error if service failed to load a url. I have created a angular factory which is like this:
loadUsers: function () {
return $http.get(urlService.url("/users"));
},
in controller i try to using this factory method to load ruserlist:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.finally(data.bind(undefined, result));
at this point i want to handle http error but not getting idea where i have to use error function as this is returning a promise. Can someone give me hint.
Just add a .catch to your promise:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.catch(function(err) {
console.log(err);
})
.finally(data.bind(undefined, result));
add a second callback to the .thenmethod, that will be triggered in case of error.
from the angular doc:
https://docs.angularjs.org/api/ng/service/$http
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Just add another function inside promise like this
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
},function(response) {
$log.info("error");
})
.finally(data.bind(undefined, result));
urlservice.loadUsers().then(successCallback, errorCallback)
.finally(data.bind(undefined, result));
var successCallback = function(response) {
// handle data recieved
$log.info("user loaded");
};
// create generic method for handling service errors
var errorCallback = function(error) {
// handle error here
$log.info("error occurred");
};

Angular HTTP Interceptor not hitting error functions

So I have pulled the interceptor straight from the angular HTTP documentation and yet this still doesn't work. The "request" and "response" functions get called ,but never the "requestError" or the "responseError".
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($q) {
return {
'request': function (config) {
return config; //gets called
},
'requestError': function (rejection) {
return $q.reject(rejection); //Never gets called
},
'response': function (response) {
return response; //gets called
},
'responseError': function (rejection) {
return $q.reject(rejection); //Never gets called
}
};
});
}]);
On the server I am returning a 400, but really any error would do. And here is the service
User.publicProfileGetProfile = function (value, type) {
return $http({
url: '/public/profile/' + type + '/' + value,
method: 'GET'
}).then(function (response) {
return response;
}, function(error){
return error;
});
};
No error functions are being called and every response goes through the response function. The standard angular error is displayed with the Bad Request (400) as usual. When the 400 error is returned, it is simply 'undefined' through the 'response' function in the interceptor.
Let me know if I've forgotten to include any important information.
By using return, the error handler is converting the rejection to a success. Instead use throw to chain the rejection.
User.publicProfileGetProfile = function (value, type) {
return $http({
url: '/public/profile/' + type + '/' + value,
method: 'GET'
}).then(function onSuccess(response) {
return response;
}, function onReject(error){
//return converts rejection to success
//return error;
//use throw to chain rejection
throw error;
});
};
When I saw that the JSFiddle (from #georgeawg) was working properly, I made sure mine looked exactly the same. When it didn't work, I looked around to see if I had any other interceptors that might cause problems. I had another interceptor that was being hit first and returning any errors as responses, then they would go through this one and it would process it as a successful response. I removed it and everything seems to be working correct now!

Can I handle an error from the gapi.client.load's promise?

Question if gapi.client.load returns the promise was discussed here. And as Mike Witt answered, the code:
gapi.client.load('guestbook', 'v1', undefined, '/_ah/api');
returns the promise, but without any error callback function.
I tried to handle the error:
gapi.client.load('guestbook', 'v1', undefined, '/_ah/api')
.then(
function() {
//success
},
function(error) {
//error
}
);
and when I turn off an endpoint module it will never steps into the error handler. I'm only getting a following error in a console:
GET http://localhost:8080/_ah/api/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-s…3DIQ%2Frt%3Dj%2Fd%3D1%2Ft%3Dzcms%2Frs%3DAGLTcCOu-PQv0yFB8pB9mX2w3nuej8rl5Q net::ERR_CONNECTION_REFUSED cb=gapi.loaded_0:163
Is there any way how to handle this error? I've tried to find it in docs, but without success.
After some time I have found the answer:
gapi.client.load('guestbook', 'v1', undefined, '/_ah/api')
.then(
function(response) {
if(response && response.hasOwnProperty('error')) {
// error
} else {
// success
}
}
);
In the case of some error, the gapi.client.load returns an error object e.g.:
{error: {errors: Array[1], code: 404, message: "Not Found"}}
but it has to be "caught" in the .then() not in the .catch()
You can easily test for a fail (at least now). I am pretty sure this is what you are looking for.
Here is the code:
gapi.client.init({}).then(() => {
gapi.client.load('some-api', "v1", (err) => { callback(err) }, "https://someapi.appspot.com/_ah/api");
}, err, err);
function callback(loadErr) {
if (loadErr) { err(loadErr); return; }
// success code here
}
function err(err){
console.log('Error: ', err);
// fail code here
}
Example
The syntax for this method is : gapi.client.load(API_NAME, API_VERSION, CALLBACK);
you might have a look here [1], also this stackoverflow question can help you [2].
'/_ah/api' cannot be used as a callback as it is a specific handler for testing and viewing APIs of your Google App, for example when using endpoints for mobile applications.
[1] https://developers.google.com/api-client-library/javascript/dev/dev_jscript#OptionLoadtheserviceAPIthenassembletherequest
[2] Catch Error from gapi.client.load

Categories

Resources