angularjs custom REST action and error handling - angularjs

I'm having some trouble with error handling in a little angularjs application. I'm interacting with a Flask backend and a Postgres DB.
I have a factory service
appointServices.factory('Appointments', ['$resource', function($resource){
return $resource(someUrl, {}, {
query: { ... }
,
create: {
method: 'POST'
,url: 'http://somedomain:port/new/:name/:start/:end/:treatment'
,params: { start: '#start', end: '#end', name: '#name', treatment: '#treatment' }
,isArray:false
}
});
}
]);
Inside a controller I'm making the following call
Appointments.create($scope.appointment, function(value, responseHeaders) {
// success handler
console.debug('success: ', JSON.stringify(value));
}, function(httpResponse) {
// error handler
console.debug('error: ', JSON.stringify(httpResponse));
});
Here $scope.appointment contains the relevant parameters for the create action.
Now, in the backend I'm able to catch DB errors involving constraints and I'm trying to return an error code with a 'meaningful' message. So I have a python method
def create(name, start, end, treatment):
try:
...
transaction_status = 'ok'
code = 200
except IntegrityError as e:
...
transaction_status = 'IntegrityError'
code = 500
finally:
...
return make_response(transaction_status, code)
Everything works fine, I'm able to talk to the backend, create new data and insert this in the DB. As I said, any violation of the constraints is detected and the backend responds
curl -X POST "http://somedomain:port/new/foo/bar/baz/qux" -v
...
< HTTP/1.0 500 INTERNAL SERVER ERROR
...
IntegrityError
So, the problem is, no matter whether the action create was successful or not, the intended error handler specified inside the controller is always fired. Moreover, I always end up with a status code 404 in the httpResponse. Firebug shows correctly the code 500 as above, though.
Anybody has any idea of why I'm getting this behavior?
Any suggestions on how to improve the error handling mechanism are also welcome.
Thx in advance.
P.S. Following the documentation on $resource I have also tried variations on the factory service call, e.g.
Appointments.create({}, $scope.appointment, successCallback, errorCallback);
Appointments.create($scope.appointment, {}, successCallback, errorCallback);
with the same results.
Update:
Forgot to mention the important fact that I'm interacting with the backend via CORS requests. The POST request in create above is having place with the OPTIONS method instead. As I mentioned everything is working correctly except for the error response.
Under further investigation, I tried to isolate the factory service, in case I did something wrong, and I also tried the approach shown in the credit card example ($resource docs), but with no positive result.
However, I came up with two workarounds. Firstly, I was able to create a plain JQuery POST request, as in the example shown in the docs. This time, the request is not replaced by OPTIONS and I got the error code correctly.
I also managed to connect to the backend with the low-level $http service as follows:
var urlBase = 'http://somedomain:port/new/:name/:start/:end/:treatment';
var url = urlBase.replace(/:name/g, $scope.appointment.name);
url = url.replace(/:start/g, $scope.appointment.start);
url = url.replace(/:end/g, $scope.appointment.end);
url = url.replace(/:treatment/g, $scope.appointment.treatment);
// force method to be POST
var futureResponse = $http({ method: 'POST', url: url });
futureResponse.success(function (data, status, headers, config) {
console.debug('success: ', JSON.stringify(data));
});
futureResponse.error(function (data, status, headers, config) {
console.group('Error');
console.debug(JSON.stringify(status));
console.debug(JSON.stringify(data));
console.groupEnd();
});
This time, as in the case of JQuery, the request is done effectively with POST and error codes are correctly received.
Notice also that I'm not calling $http.post but I set the method to POST as part of the object parameter to $http, otherwise the connection takes places with OPTIONS as before.
Still trying to figure out what is happening with $resource.

Related

Getting status code in AngularJS 1 on service call

Once the service call is done, I was able to see the status code in General, Response Headers in Chrome Dev Network tab for the production URL. But for the test environments, the status code is being displayed in General but not in Response Header.
Why the status code is not displayed in Response header for test Environments.
How to access status code from General Header in AngularJS.
headers().status in the transformResponse method is always fetching from Response header. So for test environments, I was not able to get the status code.
Any other way to get the status code in AngularJS, I tried passing 2nd param in the success Callback, but I don't get any value for the status code
If you're asking "How to access the status code from the response in AngularJS", it should always be in the response body.
You can get it by writing the following code in your service:
this.requestInformation = function() {
return $http({
method: 'GET',
url: 'Your url'
}).then(function (response) {
console.log(response.status)
return response;
})
}
I hope that answered your question! Let me know if it works for you.

How to authenticate a HTTP request to an OrientDB function on AngularJS?

I have the following OrientDB function:
http://localhost:2480/function/Application/getPassFailCount/9:600
And it returns the following JSON result:
{"result":[{"#type":"d","#version":0,"pass":16.0,"fail":2.0,"#fieldTypes":"pass=d,fail=d"}]}
What I need to do is to get the values of "pass" and "fail" to use in my web page.
So far I have done this with AngularJS:
$http.get('http://localhost:2480/function/Application/getPassFailCount/9:600').
success(function(data) {
$scope.data = data.result;
// $scope.passCount = ;
// $scope.failCount = ;
});
Currently it gives the error "401 Unauthorized". How do I authenticate the request?
And if possible, can anyone give some tips on how to get the passCount and failCount from the JSON result returned?
The OrientDB HTTP API documentation states that you have to use HTTP Basic authentication for issuing commands. That means you have to include an Authorization header along with your request.
There are a few ways to achieve this, here is a simpler one. Use the configuration object parameter for $http.get to set the header on the request:
function base64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
$http.get('http://...', {
headers: { 'Authorization': 'Basic ' + base64(user + ':' + password) }
}).success(...);
You should definitely move all your database logic to an Angular service, so you can keep this code in one place instead of polluting your controllers.
To make it even cleaner, you could look into $http interceptors and write a request interceptor that adds the header to every HTTP call.
Regarding the JSON question: you can see that the result object contains an array with a single element. Use indexing to get the actual record.
var result = data.result[0];
$scope.passCount = result.pass;
$scope.failCount = result.fail;
If you wrote a service as I mentioned, you could hide this implementation detail from your controller.
function getCount() {
return $http.get(...).then(function (data) {
var result = data.result[0];
// the caller will only see this simpler object
return { pass: result.pass, fail: result.fail };
});
}

How to catch wrong password/username response in angular?

I’m trying to implement authentication in my angularjs app.
I’ve read some articles about doing this properly. Here is one, for instance: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
But I can’t realize how to make it respond on wrong username/password pair.
Let’s have a look at this code :
authService.login = function (credentials) {
return $http
.post('/login', credentials)
.then(function (res) {
// populate user info
}
);
};
I’ve tried to add here a second callback to “then” method and use “success”/”error” methods instead of “then” and I’ve tried to response on $http.post request with different error like 400 and 500 via status, but in any case all the errors are handled by the success method and callback.
What am I doing wrong? How to catch wrong password/username response in angular?
It was actually my own fault. My custom Intereptor simply swallowed authenticaion errors.

Angular REST returning Syntax error on JSON parse

I am getting an error "syntax error JSON parse unexpected end of data at line 1 column 1 of json data". The RESTful service is runnning, a straight test returns valid json data (verified at http://jsonlint.com/)
[{"id":2,"name":"Flourescent Penetrant Inspection","description":"The fluorescent penetrant inspection process.","abbreviation":"FPI","tempId":null,"processType":"INSPECTION","indicationTypes":[{"id":1,"name":"Crack","description":"An identified crack on the piece.","abbreviation":"","tempId":null,"groupName":"","markupType":"LINE","useSizeDescription":true,"sizeDescription":"<= 1 in.::> 1 in.","rejectReason":"Crack","defaultDisposition":"MRB"},{"id":2,"name":"Inclusion","description":"An identified inclusion on the piece.","abbreviation":"","tempId":null,"groupName":"","markupType":"DOT","useSizeDescription":false,"sizeDescription":"","rejectReason":"Inclusion","defaultDisposition":"REWORK"}]},{"id":4,"name":"CMM","description":"The CMM process.","abbreviation":"CMM","tempId":null,"processType":"INSPECTION","indicationTypes":[]}]
The error in the HTTP response, yet it is returning a 200 message. The angular app is seeing it as an empty array. Any ideas?
The applicable part of the Controller is:
indicationTypeController.constant("indicationTypeUrl", "http://localhost:8080/services/api/indication-types.json");
indicationTypeController.controller('indicationTypeController', function ($scope, $http, $resource, indicationTypeUrl) {
$scope.indicationTypeResource = $resource(indicationTypeUrl+":id", { id: "#id" },
{ 'create': {method: "POST"}, 'update': {method: "PUT"}
});
$scope.listIndicationTypes = function () {
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data;
});
//$scope.indicationTypes = $scope.indicationTypeResource.query();
}
. . . .
As you can see I am currently using a $http.get, I also tried a query().
Any
Usually, the $http promise returns an object that contains the headers and the data. In your success handler for the $http, you have
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data;
});
I'm pretty sure that data is the full response and you need to get the specific data by using the data property of this object. Therefore, this would become the following:
$http.get(indicationTypeUrl)
.success(function(data){
$scope.indicationTypes = data.data;
});
In other implementations, instead of the passed in parameter being called data, it's usually called result, so that you can reference the contained data like result.data instead of data.data
The other thing to make sure of is that the Content-Type is set appropriately between the server and client. If it's not application\json you'll probably run into issues.
This is an CORS issue, please add the following to the response header, before sending the result.
"Access-Control-Allow-Origin" : "*"
For instance, if you are using play server (Java code) to serve the request, the following statement should be added to the method where you are returning the data from
response().setHeader("Access-Control-Allow-Origin", "*");

angularjs $http.jsonp goes to .error instead of .success even when 200 is received

I'm building an AngularJS app which calls a NodeJS server that gets data from a DB.
The NodeJS returns a JSON.stringify(someArrayWithData).
Here is the AngularJS code:
$scope.getMainGroups = function(){
$http.jsonp("http://127.0.0.1:3000/get/MainGroups?callback=JSON_CALLBACK").success(function(data, status, headers, config) {
$scope.MainGroups = data;
}).error(function(data, status, headers, config) {
$scope.MainGroups = status;
});
};
$scope.MainGroups is going to the .error instead to the success even when I can see in the chrome debugger that the result came back (200 ok).
What am I missing?
You must return a valid JSON response on the server side. The 200 OK is just the GET request that is injected into the DOM. I bet you are not returning a valid JSON response from the server with right response code.
Here is an example on how to construct the response on the server side (PHP):
Simple jQuery, PHP and JSONP example?
As answered here you need to change the NodeJS response. The JSONP answer needs to start with the exact text that AngularJS added in the URL (for example 'angular.callbacks._1').
// changes in your server script used by NodeJS
// Required for JSONP calls, 'callback' matches the '?callback=JSON_CALLBACK'
app.set('jsonp callback name', 'callback');
// ... in your response change json to jsonp
res.jsonp(votes);
After doing these changes, when the server detects a 'callback' in the parameters, answers like this:
/**/ typeof angular.callbacks._1 === 'function' &&
angular.callbacks._1([{"votes":3,"title":"new topic", etc...
Now yes, AngularJS correctly calls back the 'success' function.

Resources