i want to use $promise.then(successCallback,errorCallback) after the interceptor did the basic message handling. Somehow it always runs into the successCallback and never into the errorCallback if i get error 400,401 etc. If i remove the interceptor it works fine. I also found out that i could create a new promise in the interceptors to solve this problem but i think this is not the best way to go. In my case i only want an interceptor for some basic message handling and then continue in the main controller with the main logic. This is currently not possible because i always run into the successCallback if i get an error.
Did i understand something wrong?
Here an example what i want:
var resourceObj = $resource("url/abc/:action/:id", {}, {
getMember: {
method: 'GET',
params: { action: 'member' },
interceptor: {
responseError: function(response) {
console.log("Interceptor responseError");
//Show some default error messages here
return response; //create new promise with $http(response); to solve the problem?
},
response: function(response) {
console.log("Interceptor responseSuccess");
//Show some default success messages here
return response; //create new promise with $http(response); to solve the problem?
}
}
}
});
myModule.controller('myCtrl', function($scope) {
$scope.checkMember() = function(memberId) {
resourceObj.getMember({ id: memberId }, {}).$promise.then(
function(responseOK) { //successCallback
console.log(responseOK);
$scope.testMember = responseOK.data; // or if no interceptor is used responseOK.toJSON()
//do some stuff here after async call is finished
},
function(responseError) { //errorCallback, never called in error case if an interceptor is used.
console.log(responseError);
//do maybe some advanced error handling here after async call is finished
}
);
}
});
It is important to re-throw the error response.
var resourceObj = $resource("url/abc/:action/:id", {}, {
getMember: {
method: 'GET',
params: { action: 'member' },
interceptor: {
responseError: function(response) {
console.log("Interceptor responseError");
//Show some default error messages here
̶r̶e̶t̶u̶r̶n̶ ̶r̶e̶s̶p̶o̶n̶s̶e̶;̶
//IMPORTANT re-throw error response
throw response;
},
response: function(response) {
console.log("Interceptor responseSuccess");
//Show some default success messages here
return response;
}
}
}
});
If the error response is simply returned, it will be erroneously converted from a rejection to a success.
I currently have an error intercept set up in AngularJS to catch any failed HTTP requests so that I can notify myself when it occurs. Occasionally (but often enough) I get an error with a status of -1. I have no idea what this means or why its occurring... Anyone have any explanations?
appService.factory("$errorInterceptor", ['$q', '$injector', function ($q,$injector) {
var errorInterceptor = {
responseError: function (response) {
var $http = $injector.get('$http');
if (response.status !== 401 && response.status !== 409) {
var error = {
status: response.status,
message: JSON.stringify(response),
url: window.location.href,
};
$http.post("/api/errors/angular", error);
}
return $q.reject(response);
}
}
return errorInterceptor;
}])
and the repsponse I'm getting is..
{"data":null,"status":-1,"config":{"method":"PUT","transformRequest":[null],"transformResponse":[null],"url":"/api/baskets/changedeliverymethod/10","headers":{"Accept":"application/json, text/plain, */*"}},"statusText":""}
EDIT:
I have never actually been able to produce this myself. Just get it randomly from all types of devices/browsers.
I'm trying to write a unit test for my Angular Service and here's a function in the service:
login = function(authObject) {
deferred = $q.defer();
$http({
url: '/api/v1/session/create',
method: 'POST',
data: authObject
}).success(function(response) {
var user;
if (response.status === 'ok' && response.user && response.authenticated === true) {
user = response.user;
}
return deferred.resolve(response);
}).error(function(data) {
deferred.reject(data);
return $state.go('api_error');
});
return deferred.promise;
};
I can successfully test the success case with something like:
it('should go to the api error state', function() {
var authObject;
authObject = {
username: 'a#b.com',
password: 'c'
};
$httpBackend.expectPOST('/api/v1/session/create').respond(someData);
userService.login(authObject).then(function(response) {
return console.log("not error", response);
}, function(response) {
return console.log("error", response);
});
return expect($state.go).toHaveBeenCalledWith('api_error');
});
That works fine, however if I do:
$httpBackend.expectPOST('/api/v1/session/create').respond(500, 'error');, then the error case doesn't get called. What am I doing wrong?
In order for your .then() error callback to be called, the previous promise in the chain should result in error (e.g. throw an Exception) or be rejected.
Returning 500 will cause the error callback in your login() method to be called, but since that callback neither throws an Error nor gets rejected, your chained error callback won't be called.
E.g. changing:
}).error(function(data) {
deferred.reject(data);
return $state.go('api_error');
});
to:
}).error(function(data) {
return deferred.reject(data);
//return $state.go('api_error');
});
would work (but it doesn't do what you want :D).
I am not familiar with ui-router, but in this case it could be possible that $state.go() aborts the current execution chain, so I am not sure the following would work:
}).error(function(data) {
$state.go('api_error');
return deferred.reject(data);
});
In Angular, I would like to have a function that intercepts the $resource response before it gets to the controller to see if it has an error flag set and then act on that error flag. Is there a resource function I can hook into to check the response data before it sends it on it's way to the controller?
Sample resource :
mymod.factory('setSomething', function($resource){
var resource = $resource('/proxy/request.php?action=setSomething', {}, {
post:{
method : "POST",
isArray : false,
headers : {
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'
}
},
});
return resource;
});
You can define error handling for resources globally:
$httpProvider.interceptors.push(function($q, $rootScope) {
return {
'request': function(config) {
// intercepts the request
},
'response': function(response) {
// intercepts the response. you can examine things like status codes
},
'responseError': function(response) {
// intercepts the response when the response was an error
}
}
});
The response parameter gives you a lot of information to work with so you can handle errors appropriately.
Using ngResource in AngularJS 1.2rc(x), how do I get the status code now?
RestAPI.save({resource}, {data}, function( response, responseHeaders ) {
});
where RestAPI is my ngResource.
The response has the $promise object and the resource returned from the server but not a status anymore. The responseHeaders() function only has a status if the server injects the status code into the header object, but not the true returned status code. So some servers may serve it and some might not.
You can use the promiss callbacks then, catch and finally after the $resource call.
For example. If you want to catch an error after a call, you would do something like this:
RestAPI.save({resource}, {data}, callbackFunction).$promise.catch(function(response) {
//this will be fired upon error
if(response.status == 500) alert('Something baaad happend');
}).then(function() {
//this will be fired upon success
});
The response object will have status and the statusText properties. status being an integer status code and statusText the text. You'll also have the data property containing the server response.
edit: as suggested, it was response.status
You must add an interceptor inside your resource declaration. Like this:
var resource = $resource(url, {}, {
get: {
method: 'GET'
interceptor: {
response: function(response) {
var result = response.resource;
result.$status = response.status;
return result;
}
}
}
});
Usage:
resource.get(params, function(result) {
console.log(result.$status)
});
IMO status code should have been provided by default.
There is an issue for this https://github.com/angular/angular.js/issues/8341
For anyone using a newer version of Angular, looks like we've had access to the status code as a 3rd param to the transformResponse function since angular 1.3, but it was never documented properly in the $resource docs.
I agreed responseHeaders() function will only return response's header,but you can custom it and it's useful anyway.
1.
To solve you problem. With the following:($$service is my $resource instance.)
var serve = new $$service();
serve.id = "hello_wrongPath"; // wrong path,will return 404
serve.$get()
.then(function (data) {
console.log("~~~hi~~~");
console.log(data);
return data;
})
.catch(function (error) {
console.log("~~~error~~~");
console.log(error);
console.log(error.status); // --> 404
console.log(error.statusText); // --> "Not Found"
console.log(error.config.timeout); // --> 5000
console.log(error.config.method); // --> GET
console.log(error.config.url); // --> request url
console.log(error.headers("content-type"));// --> "text/plain"
return error.$promise;
})
.finally(function(data){
console.log("~~~finally~~~");
console.log(data); // --> undefined
});
In this way,u can only catch status,statusText,timeout,method,headers(same with responseHeaders) in ERROR response.
2.
If you want to see response details in success response,I used a interceptor like this:
ng.module("baseInterceptor", [])
.factory("baseInterceptor", ["$q", function ($q) {
return {
'request': function (config) {
console.info(config);
//set timeout for all request
config.timeout = 5000;
return config;
},
'requestError': function (rejection) {
console.info(rejection);
return $q.reject(rejection);
},
'response': function (response) {
console.log("~~interceptor response success~~");
console.log(response);
console.log(response.status);
console.log(response.config.url);
return response;
},
'responseError': function (rejection) {
console.log("~~interceptor response error~~");
console.log(rejection);
console.log(rejection.status);
return $q.reject(rejection);
}
};
}]);
and then add interceptor to module:
.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push("baseInterceptor");
}])
You can get response status like this:
$http.get(url).then(function(response){
console.log(response.status); //successful status like OK
}, function(response){
console.log(response.status); //error status like 400-Bad Request
})
I'm using AngularJS v1.5.6, and I do it like this (in my case I put the "getData" method inside a service):
function getData(url) {
return $q(function (resolve, reject) {
$http.get(url).then(success, error);
function success(response) {
resolve(response);
}
function error(err) {
reject(err);
}
});
}
then in the controller (for example), call that like this:
function sendGetRequest() {
var promise = service.getData("someUrlGetService");
promise.then(function(response) {
//do something with the response data
console.log(response.data);
}, function(response) {
//do something with the error
console.log('Error status: ' + response.status);
});
}
As documentation says, the response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
See https://docs.angularjs.org/api/ng/service/$http
Hope it helps!
I think the right answer is a combination of Bardiel's and Ara's answers.
After adding an interceptor inside your resource declaration. Like this:
var resource = $resource(url, {}, {
get: {
method: 'GET'
interceptor: {
response: function(response) {
var result = response.resource;
result.$status = response.status;
return result;
}
}
}
});
Use it as below:
RestAPI.save()
.query(function(response) {
// This will return status code from API like 200, 201 etc
console.log(response.$status);
})
.$promise.catch(function(response) {
// This will return status code from server side like 404, 500 etc
console.log(response.status);
});
I had faced the similar problem.I looked into the angular lib and added a few lines to have status returned in the response itself.In this file,find where promise is being returned.
Replace code block starting with
var promise = $http(httpConfig).then(function(response)
with the following
var promise = $http(httpConfig).then(function(response) {
var data = response.data,
promise = value.$promise;
if (data) {
// Need to convert action.isArray to boolean in case it is undefined
// jshint -W018
if ( angular.isArray(data) !== (!!action.isArray) ) {
throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
'response to contain an {0} but got an {1}',
action.isArray?'array':'object', angular.isArray(data)?'array':'object');
}
// jshint +W018
if (action.isArray) {
value.length = 0;
forEach(data, function(item) {
value.push(new Resource(item));
});
} else {
copy(data, value);
value.$promise = promise;
}
}
value.status = response.status;
value.$resolved = true;
response.resource = value;
return response;
}, function(response) {
value.status = response.status;
value.$resolved = true;
(error||noop)(response);
return $q.reject(response);
});
or you can add this line
value.status = response.status;
and then access status in code like reponse.status.Though,this is kind of hack but worked for me.I also had to make changes in the minified version.