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);
});
Related
I have a helper function:
function httpRequestHelper(body) {
return fetch(`${host}:${port}`, {
method: 'post',
body: JSON.stringify(body)
})
.then(function (response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then(function(response) {
if (response.type === 'error') {
throw Error(response);
}
return response;
})
.catch(function(error) {
return error;
});
}
that I wrote to keep functions for various commands short. These functions just specify the body to be sent and what part of the response is relevant to the consumer:
function hasActiveProject() {
return httpRequestHelper({ type: 'request', cmd: 'has_active_project' })
.then(function (response) {
return response.payload.value;
})
}
I execute the various commands like this:
try {
let hasActiveProjectResponse = await otii.hasActiveProject()
console.log(hasActiveProjectResponse);
} catch (error) {
console.log(error);
}
Now the problem is that in the catch function I would expect to get the error message thrown, but instead I get error messages like:
TypeError: Cannot read property 'value' of undefined
This is because hasActiveProject() tries to extract the relevant response even when there was an error and that causes a different error that is returned to my catch (error) handler.
How can I rewrite this so that
hasActiveProject() remains thin
The catch handler receives the original error
Are you sure you have an error? and response.payload is not undefined? because in this test fiddle you can see that its working as you want it to, the try catches the errors thrown inside the .then function, and doesn't continue.
https://jsfiddle.net/8qe1sxg4/6/
It looks like response.type is valid, so you don't have any errors thrown, can you confirm the results you get?
UPDATE
After some more researching, the catch function doesn't bubble to the next catch, it considered as if you already handled the error and continue as usual (with the resolved value from the catch).
But you can simply reject again inside the .catch(), so this way your error will bubble to the try/catch:
in httpRequestHelper():
.catch(function(error) {
return Promise.reject(error)
//return error;
});
This will send your error to the next catch, see fiddle for example:
https://jsfiddle.net/dcuo46qk/3/
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
does it make sense to call the same http request call within the catch if the first one fails but with different parameter in order to return some default data ?
var defaultData = false;
clientService.getClients(defaultData)
.then(function (res) {
//do something
}).catch(function (err) {
defaultData = true;
clientService.getClients(defaultData)
.then(function (res) {
//do something
}).catch(function (err) {
console.log(err)
});
});
or this is a bad way ?
Be sure to return the new promise to the catch handler. The code will then chain properly and it avoids nesting:
clientService.getClients({defaultData:false})
.catch(function (err) {
return clientService.getClients({defaultData: true})
}).then(function (res) {
//return something
}).catch(function (err) {
console.log(err)
//IMPORTANT re-throw err
throw err;
});
This issue not bad but I think you have to find reason of the failure and on the furniture do some action.
the best is that you have to create an error handler like:
errorHandler(error:any){
///.....
}
In this method you should check status code of response, for instance if it is 500, you can't call again. or some thing like this.
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!
i have following function in the AbgularJS service:
var readFile = function (path, file) {
console.info("Trying to read file with URI: " +path+ " "+file);
$cordovaFile.checkFile(path, file).then(function (success) {
console.log(success);
var deferred = $q.defer();
$cordovaFile.readAsText(path, file)
.then(function (success) {
// success
console.log("Success");
console.log(success);
deferred.resolve(success);
}, function (error) {
console.error(error);
deferred.reject(error);
});
return deferred.promise;
}, function (error) {
console.log(error);
});
}
in the success callback is defined function for file reading.
But i always get exception message on this place:
TypeError: Cannot read property 'then' of undefined
But if i do following:
$cordovaFile.checkFile(path, file).then(function (success) {
console.log(success);
}, function (error) {
console.log(error);
});
it works fine.
I would like to execute file reading only if file is exist, but i don;t know hot to do it in the right way.
Service method is called by this way:
DeviceSrv.readFile(cordova.file.externalRootDirectory+"/"+APP_CONST.MP3_FOLDER_NAME+"/sounds/", APP_CONST.MP3_FILE_NAME)
.then(function(value){
console.log(value);
var parsedObject = JSON.parse(value);
console.log(parsedObject);
$scope.availableSounds = parsedObject.availableSounds;
$scope.availablePrepreparedSounds = parsedObject.availablePrepreparedSounds;
});
How i should update my code to execute code in the right way?
Many thanks for any advice.
Since promises can be chained, you can just return the entire promise, without the need for creating deferred.
var readFile = function (path, file) {
console.info("Trying to read file with URI: " +path+ " "+file);
return $cordovaFile.checkFile(path, file).then(function (success) {
return $cordovaFile.readAsText(path, file);
}).then(function (success) {
// success
console.log("Success");
console.log(success);
}).catch(function (error) {
console.error(error);
});
}