POST Behavior Between $http and Restangular - angularjs

I have a simple ASP.NET Web API 2 service. I'm new at Angular, but I'm trying to switch from using $http to Restangular. My GET appears to be fine, but my POST is not.
The code looks like this:
$scope.addLift = function () {
$http.post(url, $scope.Lift);
//Restangular.all('lifts').post('Lift', $scope.Lift).then(function (newLift) {
// $scope.getLifts();
//}, function (error) {
// console.log(error);
//});
};
The commented out Restangular code does not work, but the $http.post does and I'm not sure what I'm doing wrong.
If it's helpful, the POST when using Restangular is http://localhost/api/lifts?LiftName=test where in the $http POST request, it does not contain the parameters on the URL line, it seems the data is in the request body.

Someone on another website was kind enough to help me through this. Thought I would post the answer in hopes that it might benefit others.
Restangular.all('lifts').post($scope.Lift).then(function (newLift) {
$scope.getLifts();
}, function (error) {
console.log(error);
});
The additional 'lift' argument was not necessary in the post call.

Related

AngularJS ngResource delete event not calling callback

I have this code:
dogsResource.delete({id: $stateParams.dogId}, angular.noop,
function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
The delete is done, the problem is that neither success nor error is being called. I've also tried using an instance (that means, to use $delete), but it didnt work either.
I tried testing the callbacks with other methods, such as get
$scope.dog = dogsResource.get({id: $stateParams.dogId}, function(value, res){
console.log(value);
});
And it works. I don't know why that happen, since the dog is being deleted from database.
Thanks
UPDATE
dogResource code
// Return the dogs resource
.factory('dogsResource', ['$resource', function($resource){
return $resource("http://localhost:5000/dogs/:id",{id: "#id"},{update: {method: "PUT"}});
}])
UPDATE 2
I Found the error. It was in the RESTful API (Node js). The method was not sending anything to Angular, so no callback was triggered:
//DELETE - Delete a dog with specified ID
exports.deleteDog = function(req, res) {
console.log('DELETE' + req.params.id);
Dog.findById(req.params.id, function(err, dog) {
dog.remove(function(err) {
if(err) return res.status(500).send(err.message);
console.log('Succesfully deleted.');
res.status(200);
})
});
};
Replacing res.status(200) with res.status(200).end() got the callback triggered.
Thanks you all for your time.
I suggest to you to not use
res.status(200).end()
In fact usually when you delete an object with a REST service in expressJS, the common case is to send the deleted object as response, because it could be useful for the frontend to get this object (and to make sure that it's the good object).
So instead of use
res.status(200).end()
use
res.send(dog)
Or if you want to send an empty response, the status code for a delete operation should be :
res.status(204).end()
204 NO CONTENT
Note that you don't need to set the status code by default it will be 200. So set status code to 200 is just useless.
And to finish an http response needs to be sent to close the request. The end method or the send method make that. Set a status code to a response http will never send anything to the frontend. That's why your angular callback was never fired.
So i suggest to you to add the tag expressjs to your question, because it's not an AngularJS problem but a real expressJS mistake.
In your code, the second argument is angular.noop:
dogsResource.delete({id: $stateParams.dogId}, angular.noop,
function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
According to the ngResource Source Code, if you set the second argument to a function (angular.noop is a function) then it will use the second argument as the success callback. Since the second argument is a no-operation, nothing will happen when it is called.
Try setting the second argument to function (r) { console.log (r) } and see what you get.
I'm recently working with ngResource. In my case, I've have used three parameters in that api call. Therefore, you could use
dogsResource.delete({id: $stateParams.dogId}, function(value, responseHeaders){
//Success
console.log(value);
console.log(responseHeaders);
},
function(httpResponse){
//Error
console.log(httpResponse);
}
);
I hope that helps.
Use promise return by the $resource object. As $resource object by default return a promise object, and that promise object is available .$promise variable over that $resource API method.
Code
dogsResource.delete({id: $stateParams.dogId}).$promise.then(function(data)//Success
console.log(value);
},
function(httpResponse){ //Error
console.log(httpResponse);
});

AngularJS handling Server HTTP 403/40X

I have standard functions in my frontend AngularJS 1.x application (with ui-route) which looks like the one at bottom.
My question now would be what to do if e.g. HTTP 403 appears. Is there a best practive approach how to redirect to loginpage in AngularJS.
I would be thankful for all hints in this direction.
Thanks a lot!
function getSomethingFromServer(someParameters) {
return $http.get(api_config.BASE_URL + ...', {
}).success(function(data) {
console.log('got data from server');
}).error(function(data) {
console.log('error getting data from server'); // in my case HTTP 403 appears if token is not valid any more
});
}
Take a look at the the $http service in the angular docs and in particular response interceptors - https://docs.angularjs.org/api/ng/service/$http

Prevent $http service execution using Interceptor

I am building an authentication solution with Angular. I am using Interceptors to validate Request and if there is not valid token prevent from further processing and redirect. Here is my simplified Interceptor:
prism.service('APIInterceptor', function($rootScope) {
var service = this;
service.request = function(config) {
.....
return config;
};
})
Just for the sake of POC that I am working on what would the correct way of stopping this request from any further processing be?
Thanks
From the Angular Docs on Interceptors for the request method:
request: interceptors get called with a http config object. The function is free to modify the config object or create a new one. The function needs to return the config object directly, or a promise containing the config or a new config object.
The rest of the documentation can be found here. From this you can see that the method can also return a promise (which is actually pretty awesome) so you could always reject it.
Try something like this:
prism.service('APIInterceptor', function($q, $rootScope) {
this.request = function(config) {
if( /*config is not valid*/ ) {
return $q.reject({message: 'ERROR, ERROR... INTRUDER ALERT!', status: 401, config: config});
} else {
return config;
}
};
});
And see how it might be handled (I have no idea what your application will do). Let me know if it works out for you!
EDIT: My answer has been accepted, but is incomplete and it will haunt me forever if I don't complete it. So, after writing some test code of my own I've realized that you can do 1 of 2 things in this situation. The first is to handle the unauthorized request in the interceptor:
...
this.request = function(config) {
if(/* config is not authorized */) {
// Do something here like redirect/issue another request... whatever
return $q.reject({/*whatever the hell you want*/});
} else ...
};
...
This obviously works best if you want to handle all unauthorized requests the same. If you don't, however, the second option is to defer to the service that issued the request. For example, if you're using $http you can do this:
$http.get('/words/words/words/').then(function(){
// This is where you handle a successful request.
}, function(error) {
// Handle your error here. Please take note that this error message is
// whatever you sent back in the `reject` previously
});
Hopefully that clears a few things up.

angular-http-auth with $http transformResponse

I'm using angular-http-auth to show a login dialog whenever a 401 "unauthorized" response is returned from the server.
Since I'm cool, I also try to deserialize response objects in my services. For example, if a service requests a car and the response is {make: Honda, model: Civic}, I try to deserialize that into a Car object using transformResponse.
For example:
getCar: function() {
return $http.get('/api/car', {
method: 'GET',
transformResponse: function(data, headers) {
var c = angular.fromJson(data);
return new Car(c);
}
});
}
This doesn't work with angular-http-auth. If the response was a 401 Unauthorized, you'll get a javascript error. It's because angular will try to run that transformResponse code even if the response was a 401.
It turns out that $http interceptors (which is what angular-http-auth uses) are run AFTER the transformResponse code. That's a huge problem, because none of that code in transformResponse will work if the server response was a 401 (there wouldn't be any data)
Is this a problem for anyone else? How did you get around it? Am I not to use transformResponse if I use $http interceptors?
Late to the party, I know, but to anyone coming here from Google like I did (I also posted this as a comment on a related issue filed with the Angular repo):
I also found it to be confusing that response interceptors run after the transformResponse method. I added a method to $http.defaults.transformResponse. Here is an example from the documentation on how to do that.
So, if you need to basically have a response interceptor that runs before the transformResponse method, this should do it:
'use strict';
angular.module('app')
.run(function ($http) {
$http.defaults.transformResponse.push(function (data, headers) {
// do stuff here before the response transformation
// Be sure to return `data` so that the next function in the queue can use it.
// Your services won't load otherwise!
return data;
});
});
If your services or http calls don't have their own response transformer, you're good now.
If your services do have their own transformResponse method, they will actually override all default transformers (I found this out after a long read of the documentation), and the above code will not run.
To circumvent this, you can follow this example in the docs.
To get around this problem I don't use transformResponse anymore. I just can't see the point of transformResponse if it runs before $http interceptors.
In order to use angular-http-auth and also deserialize responses in your services, you can write your services so that they execute the HTTP request first and then deserialize the response in a callback function.
As an example, here is how I would have restructured the example in the OP:
Plunker
services.factory('HttpCarService', function($resource, $q) {
var resource = $resource('/api/car');
return {
getCar: function() {
var deferred = $q.defer();
var car = null;
var successCallback = function(data, status, headers, config) {
var c = angular.fromJson(data);
car = new Car(c);
deferred.resolve(car);
};
var errorCallback = function(data, status, headers, config) {
deferred.reject("something wrong");
};
var result = resource.get(successCallback, errorCallback);
return deferred.promise;
}
};
});
This pattern will also work if data is an array.
$http interceptors will run before either of the callback methods are executed. If your $resource needs url params, you can make the getCar() function accept a config object as a parameter, and pass the necessary information on when you make the $resource.get() call.

$resource POST request with payload in angular

I wanted to send a post request with a payload '{}' as required for the back end . I was using angular's $resource service and was not able to achieve this . Googling I happened to see that
method(param,payload) is the way to do that , but I could not make it work .
Below is my $resource factory
.factory('Dfs',['$resource',function($resource){
return $resource('http://'+server_ip+'/jax/search/',{},
{
query:{method:'POST'}
})}])
and in the controller I am calling
.controller('DFl', function($scope,Dfs){
var d={};
Dfs.query(d,function(resp)
{
console.log(resp);
}) })
The payload I want to send is
{}
please help .
I found one
ResourceName.method(payload,function(a,b){
//Handle the response here
})
That did work ... Thank You all ..
If you just want to send a simple POST request you can use the $http service.
var url = 'http://...';
var data = {};
$http.post(url, data).then(function(result) {
console.log(result.data);
});
Here is a simple demo.

Resources