Angularjs $http put request to REST api using mongoose mongodb - angularjs

Could someone share an alternative update api with me? I have a model named "performers" which has a “score” property. I want to increment the score with a request from an Angularjs controller to the Mongo DB. I can't quite find a way to do the incrementing.
I've looked a ton of places .. here is the mongoose documentation
http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html
this another giving some clues about argument syntax
http://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
and mongo speaking directly to the $inc
https://docs.mongodb.org/v3.0/reference/operator/update/inc/#up._S_inc
heres is the request I am trying (from client side angular controller) with
example data passed ( the keys are mongodb ids)
performerScoreDeltas = { 343l88jkjkjkuuiui: -20, iii88909jkmmmkjjkj: 13, iooiuo8889ee888: -9, popopbi99r8765: 7, 898989kv908098: 5, 798v8978fw79798: 25, a90va089898as9: 9 }
//from my angularjs controller for the page
$scope.updateDbScores = function(performerScoreDeltas){
for(var eventScore in performerScoreDeltas){
$http.put('/api/performers/' + eventScore, {$inc:{score: performerScoreDeltas[eventScore]}})
}
}
// from my api for the performer model
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Performer.findById(req.params.id, function (err, performer) {
if (err) { return handleError(res, err); }
if(!performer) { return res.status(404).send('Not Found'); }
var updated = _.merge(performer, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.status(200).json(performer);
});
});
};
I've been getting 200 responses for the updates, yet the score property isn't changed. The requests get to the right place though and looking at my chrome dev tools I see the request is carrying a "payload" of {$inc:{score:-20}} for an id I want to decrease the score by by 20 etc.
Question: Do I need to make a special API route and somehow hardwire more of the $inc into it and only have the request pass data?
Here is the angularjs $http documentation
https://docs.angularjs.org/api/ng/service/$http#put
I'm stuck. The needed information seems to be getting there but maybe it is because my api controller is using the save method instead of the update method?
Could someone share with me an alternative RESTFUL api code that uses update instead? I'll admit that the block I use comes from a yeoman package. It does work well for normal updates I have implemented and even worked editing the _.merge (hmm... maybe I could change the merge to include the $inc? ...but it would need data from the params)

Related

MongoDB / Express / React - How to define the variable name which will be saved in the db

Im still new in coding and struggle on some basics.
I have to create a URL-Shortener with Express and MongoDB, additionally I use React for the frontent.
I have an input field and a submit button. The inputed URL will be sended by a POST request to the server.
(a console.log shows that this works fine)
Using "npm short-id"-package helps me to define an id for the shortUrl if the inputed url is accepted by "npm validid"- package.
Up to here, everything is fine.
Now, the "amateur-struggle" begins :)
I have learned the common pattern to save data in the mongoDB, example:
var createAndSaveUrl = function(done) {
var NEEDHELP = new Url({url: req.body.url, shortUrl: shortid.generate()});
NEEDHELP.save(function(err, data) {
if (err) return console.error(err);
done(null, data)
});
};
The "NEEDHELP" variable makes me go crazy, because I think I have to give it a unique name for the DB but dont know how to do that.
Someone can help me out?
var createAndSaveUrl = function(done) { var shortenedUrl= new Url({url: req.body.url, shortUrl: shortid.generate()});
shortenedUrl.save(function(err, data) {
if (err) return console.error(err);
done(null, data) }); };
I think this is enough.

how to check multiple responses simultanously

$scope.placeOrder = function() {
var callbackBalance = apiService.updateBalance($scope.order);
callbackBalance.then(function(data) {
if(data.data.success) {
var callback = apiService.createOrder($scope.order);
callback.then(function(data){
if(data.data.success)
{
localStorageService.cookie.clearAll();
alert("Order Placed Successfully");
$state.go("createOrder");
}
else
alert('Sorry! Cannot place order');
});
}
else
{
alert('Cannot update company balance')
}
});
This a code to place order for a company and update its balance amount according to the order total.The code works fine but according to this code first the balance amount API is called and once its response is success order API will be called and its response will be checked.But, how can we check if both are successful then only update databases for balance and order.Right now a case can be that balance is updated for a company but for some reason no order was placed.
I am using MEAN stack for my development.
You can use $q service from angular
A service that helps you run functions asynchronously, and use their
return values (or exceptions) when they are done processing. You can
create a request object like this
You can create request array and pass it to $a.all function.
var request = [apiService.updateBalance($scope.order), apiService.createOrder($scope.order)]
and use $q.all function to get provided request simultaneously
$q.all(request).then(function (response) {
}, function (error) {
});
that will get the request data simultaneously. Make sure to add $q as dependency.

Passing and retrieving complex objects from Angularjs to Web Api

I have a form in angular where a user enters various criteria which I then want to pass to Web Api and get a result after queries are run. I originally thought of this as a "Get" but had trouble passing complex objects to the Web Api. With some advice, I then used a Post and was able to pass the criteria run the query in the Web Api but I had trouble getting the result back in Angular. The Web Api method is run and gets the results. But I don't see the results in the data service.
What is the best approach where the criteria for a query is multiple fields and some are lists? I haven't been able to find any good examples.
Here is the Web Api method:
[HttpPost]
public IEnumerable Post([FromBody] FrequentPawnerReportCriteria criteria)
{
var repo = new FrequentPawnerReport();
var result = repo.GetReport(criteria);
return result;
}`
Here is the dataservice:
function getFrequentPawner(criteria) {
return $http.post("/api/FrequentPawner/Post", criteria)
.then (getFrequentPawnerComplete)
.catch(getFrequentPawnerFailed);
function getFrequentPawnerComplete(response) {
var x = response
return response.data.results;
}
function getFrequentPawnerFailed(error) {
alert("XHR failed for frequent pawner report: " + error.responseText);
}
}
And here is the controller code:
function getTopPawnerResults(criteria) {
return DataContext.getFrequentPawner(criteria)
.then(
function (result) {
vm.frequentPawnerReport = result.data;
return vm.frequentPawnerReport;
});
}
Simply use JSON. Use JSON.stringify() to parse JSON object to string and POST it. Similarly, return JSON string from server, and assign it to variable in Angular. It will be automatically converted to JSON object.
I think when you make your post request, you need to have a callback function that would get invoked when your Web Api returns. Within that callback function you can update your $scope variables which will make your web ui show the response from the server. You can find an example of what I mean here: https://docs.angularjs.org/api/ng/service/$http
The gist of it:
$http({
method: 'POST',
url: '/path/to/your/web/api',
function(success) {
console.log('Successfully executed the api call');
$scope.response = response; // change this to match the data you are expecting from the server response
},
function(failure) {
console.error('There was an error');
$scope.failure = failure; // change this to match your failure response
}
);
Thanks for responding. The project is a mix of web forms and angularjs. I am migrating the app and didn't notice this form had a conflict which was causing a post back and making it look like the result was not being returned. I took the form into a separate project and was able to get the results I was going for.

Braintree Dropin UI does not work with Ionic Framework unless force refresh

I encounter a very strange behavior with Braintree dropin UI inside Ionic framework.
So I use the solution: Can't create Braintree client token with customer ID
to create the logic for the first time and the return customer.
$http({
method: 'POST',
url: 'http://localhost:3000/api/v1/token',
data: {
customerId: braintreeReturnCustomerId
}
})
As I passed in the customerId in my client view. In my nodejs server, I has a logic to check to see if customerId is undefined. If it is undefined, it is first time customer. If customerId has value, it is return customer. Very straight forward like so:
app.post('/api/v1/token', jsonParser, function (request, response) {
var customerId = request.body.customerId;
if (customerId == undefined) {
gateway.clientToken.generate({}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
} else {
console.log ("using exsiting customer!");
gateway.clientToken.generate({
customerId: customerId
}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
}
});
My client is in an Ionic View. So when I pay it the first time, it knows it is frist time user, then generate customerId for me and I store it in my database. All good. Then WITHOUT refreshing (as Ionic app do not refresh when state change), I go to a different state and go back to the payment state, it does not show the store credit card. Even my server log the customerId and I know FOR SURE the server code is running the "else" part with gateway.clientToken.generate({customerId: customerId} ...
If I force refresh in the view like using
$window.location.reload(true);
right after the first time payment successfully or I just manually refresh the page in my chrome browser (as I am in Ionic Serve), the payment Dropin UI page will show store credit card from the first time payment.
I try disable view caching like "cache: false". But it does not help. I have to force refresh to make the Dropin UI works for the second time. I think it is the javascript code in dropin UI causing this issue but I do not know how to fix it...
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
The approach you've posted is extremely unsafe as it is vulnerable to Insecure Direct Object Reference (OWASP Top 10) and can easily result in cross-user charging by a nefarious user. You've essentially allowed any user to use your server to generate client tokens for any customer.
Instead, you should only generate tokens on the server to avoid user agents from choosing the id of another user. Then serve up customer ids based on a user's credentialed login and not allow them to pass in parameters to be used during clientToken generation. There are many guides online on how to build authentication. But once you have the user created on the server you can:
if (userSession == undefined) {
//or force login if you want them to sign up for your site before buying things
gateway.clientToken.generate({}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
} else {
console.log ("using exsiting customer!");
gateway.clientToken.generate({
customerId: userSession.user.BraintreeId
}, function (err, res) {
if (err) throw err;
response.json({
"client_token": res.clientToken
});
});
}
Whatever you do don't use this code, as-is, in production. I wouldn't advise debugging the front-end until you've rebuilt to fix this vulnerability as the approach will be quite different. However, if you do come back to this problem again it looks like there might be an open issue related this behavior.

angularjs custom REST action and error handling

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.

Resources