I have URL I'm using that gives a 200 OK status and a JSON payload of {error: "Invalid user"} when you do not provide a correct user on a GET request. When using this URL with Restangular, I would prefer this resulted in an error so I can handle errors in the typical way with promises, otherwise my code is going to be very messy. How would I do this?
You can specify an an response interceptor like this:
app.config(function(RestangularProvider) {
// add a response intereceptor
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
// check the response if it contains error or not.
if (typeof(response.error) !== 'undefined') {
alert('Your authentication Fail!');
return false;
};
return response;
});
});
Related
I have a function that looks like this in an angular controller:
$http.get(dataUrl)
.then(function (response) { // success getProducts
$scope.data.products = response.data;
})
.catch(function (error) {
$scope.data.error = error;
});
dataUrl is a constant and when correct returns a list of products and everything works.
Next I wanted to test the error handling.
So I changed the dataUrl to an incorrect port number to get my data.
Now my error div shows and my content div hides.
This is correct functionality.
Here is my problem.
In my div when I show error.status, it comes back as -1. The example I am following says it should be 404. Also my statusText is empty or "".
Why is my error object not populating with anything.
I originally had this set up with error function as the second callback to then().
But I get the same results either way and I think catch() is cleaner as eluded to in another posted question on stack.
From https://docs.angularjs.org/api/ng/service/$http
A response status code between 200 and 299 is considered a success
status and will result in the success callback being called. Any
response status code outside of that range is considered an error
status and will result in the error callback being called. Also,
status codes less than -1 are normalized to zero. -1 usually means the
request was aborted, e.g. using a config.timeout. Note that if the
response is a redirect, XMLHttpRequest will transparently follow it,
meaning that the outcome (success or error) will be determined by the
final response status code.
The correct URL is: "http://localhost:5125/products" (as in:
angular.module("sportsStore")
.constant("dataUrl", "http://localhost:5125/products1")
.controller("sportsStoreCtrl", function ($scope, $http, dataUrl) {
$scope.data = {};
$http.get(dataUrl)
.then(function (response) { // success getProducts
$scope.data.products = response.data;
})
.catch(function (error) {
$scope.data.error = error;
});
});
If I change it to: "http://localhost:5000/products", the ajax request is no longer going to a webserver because it cannot find deployd serving up the products collection on port 5000. So the comment from JB Nizet is correct above.
There is no server to send back 404 or 500 so the default status must be -1 and the default statusText must be "".
But if I try this: http://localhost:5125/products1, then the ajax request finds deployd, but sends back 404 because there is no products1 collection or products1 API and so no get method for a products1 collection. So deployd sends back 404 in this case:
I have an Angular application, currently an HTML file I open but it will soon be converted to a server/accessed through localhost. I use $http to access a 3rd party API (I have no control over its responses; most of the API calls work, but some don't and throw the error:
XMLHttpRequest cannot load http://api.nal.usda.gov/ndb/search/?format=json&api_key=RJEnADgGbCjfJYi0z8vuVnelYXn2Smud2Dfi2u2F&q=susage. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 404.
The API calls that throw that error are the searches that return 0 results (in the example, the database returns no results for "susage"). In the Network tab, the response can't be loaded and no response headers are listed; for other working API calls, under Response Headers, the necessary "Access-Control-Allow-Origin:*" is present.
The API definitely forms a response and tries to send it back, but fails for whatever reason. Visiting the posted url shows that response.
Why do only the empty searches throw the error when API understands and has a response for both calls, and how do I fix it? I would prefer that my frontend communicates with the API directly, as opposed to communicating with my backend which in turn communicates with the API.
For comparison, a search with results (spelling 'sausage' correctly) vs a search without results: http://imgur.com/a/ihhI1
The $http code:
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
})
In order to expose the "-1" status (timeout) to the UI, I changed the service method to simply return the promise, like this:
var search = function(query) {
return $http.get('http://api.nal.usda.gov/ndb/search/?format=json', {
params: {
api_key: usdaKey,
q: query
}
});
};
Then you can handle the error in your controller, like this:
$scope.search = function(query) {
$scope.items = [];
$scope.err = null;
foodInfo.search(query).then(function(response) {
console.log(response);
$scope.items = response.data.list.item;
}, function(e) {
console.log('Error status: ' + e.status);
if (e.status === -1) {
$scope.err = 'No data found';
}
});
};
I keep hitting a 404 "user not found" error when trying to make a PUT request with auth0.
I'm trying to update a user and making this API call with the exact endpoint their docs told me to use.
When making the call from their docs (they have a built in test), everything works fine with the body I send and I receive a 200 success message.
When I try making the same call from my app, I keep getting a 404 user not found error.
However, when I use the same endpoint with the same user_id to GET from my app, everything works fine (proving my cliendID is configured correctly).
Why is this failing?
var updateAuthUser = function(){
var request = {
"user_metadata": {
"springboardID": 100055
}
}
var update = $http.put('https://app36591925.auth0.com/api/v2/users/auth0%7C5606b3c4b0c70b49698612fc', request);
update.then(function(response) {
console.log("update success", response);
}, function(response) {
console.log("update failure", response);
});
return update;
}
Working GET request:
var getAuthUser = function(){
$http.get('https://app36591925.auth0.com/api/v2/users/auth0|5606b3c4b0c70b49698612fc')
.then(function(response){
console.log("response", response);
var deferred = $q.defer();
deferred.resolve(response);
return deferred.promise;
});
}
The endpoint to update a user is to be called with PATCH, not PUT.
https://auth0.com/docs/api/v2#!/Users/patch_users_by_id
The correct response to return in this case would be 405 Method Not Allowed, but hapi does not yet support this. See https://github.com/hapijs/hapi/issues/1534.
I am using ng-resource to do ajax request. I want to send extra info besides the data.
For example, I have an article entity on my server
exports.fetchArticle = function(req, res, next) {
var article = req.article
return res.json({data: article, message: 'success fetch article'})
}
The reason I wrap it is that, in the case of deletion, it makes no sense to send data, I can just return res.json({data: null, message: 'deleted successfully'})
on my client side, I have:
$scope.fetchArticle = function() {
Article.get({articleId: $routeParams.articleId}, function(response) {
$scope.article = response.data
$scope.ajaxSuccess = response.message
}, function(err) {
$scope.ajaxError = err.data.message
})
}
$scope.article is not an instance of ng-resource anymore, thus I can't do further request with $scope.article, i.e. this will cause error, since $scope.article is a plain json object:
$scope.article.$update(function(response) {...})
If I simply return res.json(article) from server, it works, but I can't send along the message.
The reason I dont generate the message from client but fetch from server is that, the error message is from server, I want to keep success message consistent with the error message.
Is there any other elegant way to send the message?
Assuming that all your servers responses follow this format:
{
data: {/*...*/},
message: 'some message'
}
You could use $http's transformResponse for that, so that you get an ngResource instance that is your returned object while still processing your message. For that, you need a transform-function:
function processMessage(data, message) {
//Do whatever you want with your message here, like displaying it
}
function transform(response) {
processMessage(response.data,response.message);
var data = response.data;
delete response.data;
delete response.message;
for(var attributeName in data) {
response[attributeName] = data[attributeName];
}
return response;
}
Then you can add this function to $http's default transfroms in the config of your app:
angular.module("yourApp",[/* ... */])
.config(function($httpProvider){
//....all your other config
$httpProvider.defaults.transformResponse.unshift(transform);
});
Now all repsonses from $http get transformed by this function, triggering processMessage and leaving you with a ngResource instance of the returned object.
I need to add some data to each response I send via $http in angular that will be in the response. In other works I'm trying to add an 'id' to the request because when the response is returned I need to associate it with the correct object that sent it. Is this possible? If so how would I go about it?
use interceptors, I'm quoting from the documentation:
For purposes of global error handling, authentication, or any kind of
synchronous or asynchronous pre-processing of request or
postprocessing of responses, it is desirable to be able to intercept
requests before they are handed to the server and responses before
they are handed over to the application code that initiated these
requests.
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
'request': function(config) {
config.id = generateId(); //or a timestamp maybe?
return config;
},
'response': function(response) {
// do something on success
return response;
}
};
});
then add your
$httpProvider.interceptors.push('myHttpInterceptor');