HTTPInterceptor in AngularJS - angularjs

We have APIs which returns errors inside the reponse XMLs instead of rejecting them and sending error responses.
So I have the following code to handle them,
$http({
url: apiURL,
method: "POST",
data: req,
headers: oHeaders,
dataType: "xml",
})
.success(function(data,status) {
console.log('success!!!!!');
deff.resolve(data);
})
.error(function(data,status) {
console.log('This is what I want to see!!!!!');
deff.reject(data);
});
myApp.factory('customHttpInterceptor', ['$q', function ($q) {
return function (promise) {
return promise.then(function (response) {
var parsed;
if (response.config.dataType == 'xml'){
parsed = $.xml2json(response.data);
if (parsed) {
angular.forEach(parsed, function(v, k) {
if (k == 'status') {
if (v.APIErrors) {
return $q.reject(response);
}
}
});
}
console.log(parsed);
}
return response;
}, function (errResponse) {
// do something on error
console.log('Error section in interceptor');
return $q.reject(errResponse);
});
};
}]);
What I expected to get from is that when an error is identified within the interceptor it will reject the promise and the control would get into the error section of the $http and log the "This is what I want to see!!!!!" message. But instead is show the "success!!!!!" message.
Is this the way it works or am I doing something wrong?
Ish

I see several things that seem wrong here :
Returning a result in forEach
angular.forEach(parsed, function(v, k) {
if (k == 'status') {
if (v.APIErrors) {
return $q.reject(response);
}
}
});
You probably wrote this because you're used to put return statements inside for loops. This does not work here, because you're returning from inside a function body. There is never any reason to return something in a forEach body function: this value is not going to be used by anything.
Angular Interceptor API
Maybe you just didn't show it in your code, but you have to register your interceptor.
$httpProvider.interceptors.push('customHttpInterceptor');
What's more, your interceptor does not have the correct form : in your case, it should be a object with a response method that returns a promise of a response from a response.

Related

How return the promise of $http in angularJs

I am new to AngularJS. How can I return the response of "response.data" as a typical function?
Because $http generates a promise, when the function finishes it doesn't return the server response.
In my controller I have:
this.message2 = function() {
$http({
url : 'dataset_of_model',
method : "POST",
data : {
'experiment' : 'rcp85',
'model' : 'HadGEM2-ES',
'frequency' : 'day'
}
}).then(function(response) {
console.log('qui');
console.log(response.data);
return response.data;
}, function(response) {
//fail case
console.log(response);
console.log(fallito);
return response;
});
};
If I do:
this.message2 = function() {
var = temp;
$http({
url : 'dataset_of_model',
method : 'POST',
data : {
'experiment' : 'rcp85',
'model' : 'HadGEM2-ES',
'frequency' : 'day'
}
}).then(function(response) {
console.log('qui');
console.log(response.data);
temp = response.data;
}, function(response) {
//fail case
console.log(response);
console.log(fallito);
return response;
});
return temp;
};
The return temp doesn't have the data because it returns before data, even if I wait for example 10 seconds before return.
How can I return data in a synchronous way?
Thanks!!
Try this.
this.getResults = function(){
return $http.get(url).then(function(res){
//Resquest successs
}, function(err){
//Resquest fail
});
}
And then
MyFooService.getResults().then(...);
I'm not sure why would would want to do that? You're returning response.data anyways in the first option. You should also probably add return before the $http (that way you're returning the promise). However, anything that you want to happen synchronized with the response must be in the .then block. For example, if you wanted to get a response of all goals scored, then add that number to some variable, you'd have to put that functionality in the .then block, then return the response.data at the end of the block.
That way, the functions executed inside the then block are synchronous.
You have no guarantee over the functions executed outside the then block, unless you want to hack it with $timeout (stop for 2 secs, then execute that return temp), which I don't recommend.

Any way to add local interceptor (only for one request)

Is there a way to add interceptor only specific to one particular request, like transformRespponse?
Doing like so will add global interceptor that will be executed on every request.
$httpProvider.interceptors.push(function($q) {
return {
'response': function(response) {
if (isBad(response)) {
return $q.reject(rejectionReason(response));
}
}
};
});
I think you over engineer the solution. $http already return promise with two callbacks
$http.get('your_url').then(onSuccess, onError)
function onSuccess (response) {
if (isBad(response)) {
return $q.reject(rejectionReason(response));
}
// do some magic
}
function onError(response){
return $q.reject(rejectionReason(response))
}
and really the isBad should probably happen on server side and return an http error so it's handled by onError
you can get request url inside response function
$httpProvider.interceptors.push(function($q) {
return {
'response': function(response) {
if(response.config.url == '/particular_request_url'){
//do something
}
return response
}
};
});

Force rejecting Angular $http call

I am using $http to make a call. Based on the successful result of the call I may decided to throw an error/reject and have it trickle down to the next call as an error. However if an error is thrown it just halt the process. How can I force the $http promise to reject without wrapping it in some $q code?
// A service
angular.module('app').factory('aService', function ($http, config) {
return {
subscribe: function (params) {
return $http({
url: '...'
method: 'JSONP'
}).then(function (res) {
// This is a successful http call but may be a failure as far as I am concerned so I want the calling code to treat it so.
if (res.data.result === 'error') throw new Error('Big Errror')
}, function (err) {
return err
})
}
}
})
// Controller
aService.subscribe({
'email': '...'
}).then(function (result) {
}, function (result) {
// I want this to be the Big Error message. How do I get here from the success call above?
})
In the above code I would like the Big Error message to end up as a rejected call. However in this case it just dies with the error. This is how I handle things in say Bluebird but it's a no go here.
Ti continue the Chain in a rejected state just return a rejected promise $q.reject('reason') from your $http result something like
$http.get(url).then(
function (response){
if(something){
return $q.reject('reason');
}
return response;
}
)
That way you'll get a a rejected promise and can react to it even when the api call is successful.

AngularJS Resource error callback being called with a promise

I've been writing a service in AngularJS to save some data and, if it fails, alert the user. However, after I create my resource and call $save:
myResource.$save(function(success) {
console.log(success);
}, function(error) {
console.log(error);
});
I expect the error callback's argument to be an object with data, status, headers, etc., but all I get is an object with a "then" function. I tried to mock it up in JSFiddle:
http://jsfiddle.net/RichardBender/KeS7r/1/
However, this example works as I originally expected. I yanked this JSFiddle example and put it in my project and it has the same problem I originally described, despite that as far as I can tell everything else is equal. Does anyone have any idea why this might be? My project was created with Yeoman/Bower/Grunt but I can't see why those things would make a difference here.
Thanks,
Richard
I solved the problem. The error was in my HTTP interceptor, where upon an error code, I was accidentally returning $q.reject(promise) rather than $q.reject(response).
The bugged version:
.factory('httpInterceptor', function($q) {
return function(promise) {
return promise.then(
// On success, just forward the response along.
function(response) {
return response;
},
function(response) {
// ... where I process the error
return $q.reject(promise);
}
);
};
The fixed version:
.factory('httpInterceptor', function($q) {
return function(promise) {
return promise.then(
// On success, just forward the response along.
function(response) {
return response;
},
function(response) {
// ... where I process the error
return $q.reject(response);
}
);
};
-Richard

angular jsonp factory doesn't work

I have this factory in angular, and its returning me a 0 error code always, even tho i can see it fetches from the json origin, can someone help me?
app.factory('docFactory', function($http) {
var docFactory = {
async: function(page) {
var url = 'http://example.com/ProviderRequest?&queryString=searchv2&callback=JSON_CALLBACK';
var promise = $http.jsonp(url).error(function (response, status) {
alert(status);
}).success(function (response, status) {
alert(status);
}).then(function (response, status) {
return response.data;
});
return promise;
}};
return docFactory;
});
I ran into this myself. If your JSONP is a function call or something falsy (null, false, undefined) you will encounter this behavior. Take a look at this code from AngularJS HTTP backend for more info (lines 41 - 54 are relevant).
If you are returning a function, you might just need to return true or something after the call.
Edit: After looking at your plunker it seems that your JSONP response is not calling the callback method. The response should be angular.callbacks._0( { ... } ); where { ... } is your object, and angular.callbacks._0 is the value of the callback query parameter in the request.
Your example above is almost right. Just change the callback parameter to
jsoncallback=JSON_CALLBACK
You should have something like that at the end
$http.jsonp(url + '?jsoncallback=JSON_CALLBACK').success(function(data) {
console.log(data);
})

Resources