put operation in Node.js - angularjs

For put request:
router.put('/:id', controller.update);
My update method look like this:
exports.update = function(req, res) {
if(req.body._id) { delete req.body._id; }
Thing.findById(req.params.id, function (err, thing) {
if (err) { return handleError(res, err); }
if(!thing) { return res.status(404).send('Not Found'); }
var updated = _.merge(thing, req.body);
updated.save(function (err) {
if (err) { return handleError(res, err); }
return res.status(200).json(thing);
});
});
};
Making request:
$http.put('/api/things/'+ thing._id, updatedThingObject)
.success(function(update){
console.log("update", update)
})
.error(function(err){
console.log("err", err)
})
It gives connection error on passing the object while making the request in angular.
The error looks like this:
PUT http://localhost:9000/api/things/56c8325b9a0ee7d00d266495
net::ERR_CONNECTION_REFUSED(anonymous function) # angular.js:11442sendReq #
If I take off the updated object, it makes the request just fine but ofcourse nothing gets updated in
that case. What might be wrong here,please?
I figured.
The reason for the functions not being called is that I have a function that is being called repetitively in Node .
var autoCreate = function(){
console.log("THING CREATED AUTOMATICALLY")
var randomNumb=0;
clearTimeout(randomNumb);
randomNumb = (Math.random()* (10-5) + 5).toFixed(0);
console.log("random number", randomNumb)
var randomThing =randomstring({
length: randomNumb,
numeric: false,
letters: true,
special: false
});
console.log("ranfom thing", randomThing)
Thing.create({
name: randomThing,
readByUser: false
}, function(err, thing) {
console.log("THING IS", thing)
//setTimeout(autoCreate, randomNumb * 1000);
});
}
setTimeout(autoCreate, 10*1000);
Since this is running when post/put request is made, I get connection error. How do I handle this to be able to have this function running and be able to make put/post requests as well?

Related

How to remove weird errors deleting something from a file using NodeJS + AngularJS

This question is for knowledge about how NodeJS handles HTTP responses
I'm trying to delete a field from a json file, using NodeJS and AngularJS.
The delete works, but there are two problems:
The view in the fronted doesn't get updated after the json modification (the POST function, using $scope.$apply works and updates the view)
refreshing the page shows the delete error window (why not in the current page?), but dismissing the window show the list without the selected element
What's happening, in short:
Lista (my JSON) contains A, B, C, D element -> delete(B)-> F5-> "Delete error"-> Lista contains A, C, D
My controller:
$scope.remove = function (daRimuovere) {
var del = $scope.lista3.indexOf(daRimuovere);
$http.delete('http://localhost/delete/' + del)
.then(function () {
$http.get('http://localhost/files/lista.json')
.then(
function (result) {
$scope.lista3 = result.data;
},
function () {
window.alert('Errore get!');
});
window.alert('Delete success');
$scope.$apply;
},
function () {
window.alert('Errore delete');
}
)
};
My NodeJS function
server.delete('/delete/:id', function (req, res) {
jsonfile.readFile('./public/lista.json', function (err, obj) {
if (err)
console.log(err);
else {
console.log('id= '+ req.params.id);
obj.splice(req.params.id, 1);
}
jsonfile.writeFile('./public/lista.json', obj, function (err) {
if (err)
console.log(err);
else {
console.log(obj);
obj = JSON.stringify(obj, null, "\t");
}
})
});
});
I'm answering my own question, in case someone gets strange errors from NodeJS.
The error in the Delete function is I'm not returning an HTTP explicit response, so Angular doesn't know if everything went well on the server.
My solution was this:
(...)
jsonfile.readFile('./public/lista.json', function (err, obj) {
if (err)
console.log(err);
else {
console.log('id= '+ req.params.id);
obj.splice(req.params.id, 1);
res.sendStatus(200); //this sends a OK from the server
}

Mongoose data from server (Nodejs) not displaying / .get() too late

I am just wondering if I am doing anything wrong. I save data to mongo like this:
router.route('/userAdditionalData')
//updates current user data
.put(function(req, res, next){
UserAdditionalInfo.findOne({userRef: req.body.userRef}, function(error, foundUser){
if(error){
console.log('Error in adding additional User Data: ', error);
return done(null);
};
if(foundUser){
foundUser.update(req.body, function(error, count){
res.send(200, foundUser)
});
}
else{
var addData = new UserAdditionalInfo();
addData.middleName = req.body.middleName;
addData.employer = req.body.employer;
addData.jobDescription = req.body.jobDescription;
addData.userRef = req.body.userRef;
addData.save(function(error, data){
if(error){
return res.send(500, error)
}
return res.send(200, data);
});
}
});
})
And I get the data like this:
.get(function(req, res){
UserAdditionalInfo.find(function(err, data){
if(err){
return res.send(500, err);
}
return res.send(200, data);
});
});
In my angular controller, when I get the data using $http.get():
$http.get('/api/userAdditionalData').then(function(response){
console.log('response -> ', response.data[0]);
controller.userAdditionalData = response.data[0];
});
The console perfectly logs my response, but when I log the controller.userAdditionalData I get undefined. Now, when I put a $timeout of 10 around my console.log:
$timeout(function(){
console.log(controller.userAdditionalData);
}, 10);
everything works fine. Which means that my data is being set too late. Is there something that I am not doing/doing wrong?
This is beacause the async paradigm in JavaScript. If you make an async call and outside make a log, probably prints undefined because the async is not finished. Wait for the async call with a promise or multiple promises if in a loop, when the promise ends , then you can log the value or use it.

nodejs mssql and promises confusion

I am VERY new to Promises in javascript, so this question is to help me figure out why I am getting an error (in a weird order) using a promise. On top of this, I am busy using the ms-sql repo, sinonjs and restify for the first time, so that doesn't help either
This question is related to one I asked earlier here
In the question above, I needed to stub out the SQL DB which I successfully did with the help of #robertklep. However, as a sanity check, I wanted to check that the endpoints were still returning the data I expect as before, so I undid the stubbing. Now I am getting the following error and I have no idea why:
[Error: Can't set headers after they are sent.]
Test:
'use strict';
var expect = require('chai').expect,
request = require('supertest'),
chance = require('chance').Chance(),
server = require('../server'),
sinon = require('sinon'),
select = require('../../helpers/data_access/select'),
read_file = require('../../helpers/read_file');
describe("/account_types", function () {
// before(function (done) {
// sinon
// .stub(select, "query_list")
// .returns([{id: "test"}]);
//
// sinon
// .stub(select, "query_single")
// .returns({id: "test"});
//
// sinon
// .stub(read_file, "get_file_contents")
// .returns("Some content to get excited about");
//
// done();
// });
//
// after(function (done) {
// select
// .query_list
// .restore();
// select
// .query_single
// .restore();
// read_file
// .get_file_contents
// .restore();
//
// done();
// });
it('GET 200 List', function (done) {
request(server.baseURL)
.get('/api/v1/account_types')
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.not.be.null;
expect(res.body).to.not.be.undefined;
expect(res.body).to.be.an('Array');
expect(res.body.length).to.be.above(0);
//expect(select.query_list).to.have.been.calledOnce;
return done();
});
});
it('GET 200 Single', function (done) {
//var param = chance.random();
request(server.baseURL)
.get('/api/v1/account_type/' + 1)
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.not.be.null;
expect(res.body).to.not.be.undefined;
expect(res.body).to.be.an('Object');
expect(res.body.toString().length).to.be.above(0);
return done();
});
});
it('POST 200 Single', function (done) {
var param = chance.random();
request(server.baseURL)
.post('/api/v1/account_type')
.set('Accept', 'application/json')
.send({id: param})
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.be.an('object');
expect(res.body).to.include.keys('result');
expect(res.body.result).to.equal('post account_type : ' + param.toString());
return done();
});
});
it('PUT 200 Single', function (done) {
var param = chance.random();
request(server.baseURL)
.put('/api/v1/account_type')
.set('Accept', 'application/json')
.send({id: param})
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.be.an('object');
expect(res.body).to.include.keys('result');
expect(res.body.result).to.equal('put account_type : ' + param.toString());
return done();
});
});
it('DELETE 200 Single', function (done) {
var param = chance.random();
request(server.baseURL)
.delete('/api/v1/account_type/' + param)
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json')
.expect(200)
.end(function (err, res) {
/* istanbul ignore if */
if (err)
return done(err);
expect(res.body).to.be.an('object');
expect(res.body).to.include.keys('result');
expect(res.body.result).to.equal('delete account_type : ' + param.toString());
return done();
});
});
});
Endpoints:
var select = require('../helpers/data_access/select'),
read_file = require('../helpers/read_file'),
format = require('string-format');
const db_config_name = 'db.goaml';
module.exports = function (server) {
server.get('/api/v1/account_types', function (req, res, next) {
var query = read_file.get_file_contents('path to query');
select.query_list(db_config_name, query, function (err, records) {
console.log('test 1');
if (err != null) {
return next(err);
}
res.send(records);
//return next(); <-- EDIT: Removed as per Mike Perrenoud answer
});
//return next(); <-- EDIT: Removed as per Mike Perrenoud answer
});
server.get('/api/v1/account_type/:id', function (req, res, next) {
var query =
format(read_file.get_file_contents('path to query'), req.params.id);
select.query_single(db_config_name, query, function (err, records) {
console.log('test 2');
if (err != null) {
return next(err);
}
res.send(records[0]);
//return next(); <-- EDIT: Removed as per Mike Perrenoud answer
});
//return next(); <-- EDIT: Removed as per Mike Perrenoud answer
});
server.post('/api/v1/account_type', function (req, res, next) {
res.send({'result': 'post account_type : ' + req.body.id});
return next();
});
server.put('/api/v1/account_type', function (req, res, next) {
res.send({'result': 'put account_type : ' + req.body.id});
return next();
});
server.del('/api/v1/account_type/:id', function (req, res, next) {
res.send({'result': 'delete account_type : ' + req.params.id});
return next();
});
};
select.js:
var sql = require('mssql'),
config = require('./configs/config');
module.exports = {
query_list: function (config_name, sql_query, callback) {
return query(config_name, sql_query, true, callback);
},
query_single: function (config_name, sql_query, callback) {
return query(config_name, sql_query, false, callback);
}
};
function query(config_name, sql_query, isList, callback) {
var db_config = config.get(config_name),
connection = new sql.Connection(db_config);
connection.connect(function () {
new sql.Request(connection)
.query(sql_query)
.then(function (records) {
console.log('test 3');
callback(null, isList ? records : records[0]);
connection.close();
})
.catch(function (err) {
console.log('test 4');
console.log(err);
callback(err, null);
});
});
// EDIT for answer:
// This catch is not allowed. IE the connection isn't a promise. Thus
// when the code responded with something valid, it reached this part
// after that and realised this is an illegal statement. As a result
// it throws an error after the res.send was already hit and showing the
// initial error I reported.
// .catch(function (err) {
// console.log('test 5');
// callback(err, null);
// });
}
When I run the gulp task to test the above mentioned code, I get the following output:
C:\Code\JS\general_admin_service>gulp test
[16:12:47] Using gulpfile C:\Code\JS\general_admin_service\gulpfile.js
[16:12:47] Starting 'test'...
[16:12:47] Finished 'test' after 62 ms
/account_types
1) GET 200 List
2) GET 200 Single
test 3
test 1
test 4
[Error: Can't set headers after they are sent.]
test 1
√ POST 200 Single
test 3
test 2
test 4
[Error: Can't remove headers after they are sent.]
test 2
√ PUT 200 Single
√ DELETE 200 Single
3 passing (400ms)
2 failing
1) /account_types GET 200 List:
Error: expected 200 "OK", got 500 "Internal Server Error"
at Test._assertStatus (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:232:12)
at Test._assertFunction (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:247:11)
at Test.assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:148:18)
at assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:127:12)
at C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:124:5
at Test.Request.callback (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:831:3)
at Stream.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:1049:12)
at Unzip.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\utils.js:108:12)
2) /account_types GET 200 Single:
Error: expected 200 "OK", got 500 "Internal Server Error"
at Test._assertStatus (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:232:12)
at Test._assertFunction (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:247:11)
at Test.assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:148:18)
at assert (C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:127:12)
at C:\Code\JS\general_admin_service\node_modules\supertest\lib\test.js:124:5
at Test.Request.callback (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:831:3)
at Stream.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\index.js:1049:12)
at Unzip.<anonymous> (C:\Code\JS\general_admin_service\node_modules\superagent\lib\node\utils.js:108:12)
events.js:142
throw er; // Unhandled 'error' event
^
Error: 2 tests failed.
What baffles me is that if I look at the output of the console.log's, it is clear that the code enters the "successful" then block of the sql.request and calls the callback. I can confirm that if I add a console.log to check the value the records param, there is actually data coming back in it.
At this point the res.send get's hit, but then an error is caught in the catch block of the sql.query and at this point is where the confusion hits:
If there was a successful return, why is the catch being hit?
Which part of the code is responding to the test. I.E. why is the headers being changed after it was set? (Does the next(err) perhaps have something to do with it?)
As mentioned before, this question has a lot to do with my previous one. I had to make changes to the code so as to satisfy my unit tests. However, I feel it necessary that I do a sanity check and make sure data is still being returned as expected and at this point, I think the Promise framework which ms-sql uses gets in the way of simply returning the values to the test. (I am not disputing the value of the Promise framework).
I hope someone has an idea what I am doing wrong.
EDIT:
So I am a bit confused as to what is going on. With the code as it is, if I uncomment the before and after parts of the tests, the tests fails and it looks like it has something to do with the callbacks.
If I remove the callbacks completely and have a return in the then of the sql.Request and throw err in the catches then my tests passes.
However, this setup will not return a value if I do straight up tests with no stubbing.
This is happening because you are executing a return next(); before the callback from the SQL Server has completed. The reason that's a problem is because, while it's asynchronous in nature, you're performing a synchronous set of operations overall.
What's happening is the res.send(records); is failing because next() has already been called and the server has already returned a 200.
Finally, you don't need the return next(); after the res.send(records); because res.send(records); ends the process and returns the response.

Not returning Restangular back-end call correctly

My back-end call is returning undefined. A.k.a TypeError: Cannot read property 'then' of undefined. I think I am calling it incorrectly.
Here is the AngularJS controller code:
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response, err) {
if (err) {
$scope.errorMessage = "There was an error.";
$log.debug(err);
} else if (response) {
$scope.errorMessage = "It worked.";
$log.debug(response);
} else {
$scope.errorMessage = "No 'response' nor 'err' returned from backend";
}
});
};
How this responds is that if...
(1) I put in correct credentials, I get a response that comes back with all the transaction data but still TypeError: Cannot read property 'then' of undefined in the console.
(2) Input incorrect credentials, I get no error object, response object, or even making it down to the line where I have $scope.errorMessage = "No 'response' nor 'err' returned from backend"; plus, of course, `cannot read property 'then' of undefined.
Corresponding AngularJS service:
return {
addChaseUser: function(credentials) {
return Restangular.one('user').customPOST(credentials, 'addUser');
}
};
On the backend (controller):
module.exports = {
addChaseUser: function (req, res) {
PlaidService.provideCredentialsToMFA(req.body, function (err, mfaRes) {
if (err) {
return res.status(403).json(err);
}
return res.json(mfaRes);
});
},
};
Backend service:
var plaid = require('plaid');
var plaidClient = new plaid.Client('test_id', 'test_secret', plaid.environments.tartan);
module.exports = {
provideCredentialsToMFA: function (credentials, cb) {
Q.fcall(PlaidService.connectUser.bind(this, credentials))
.then(PlaidService.saveUsersAccessToken.bind(this, credentials))
.then(PlaidService.getTransactionData.bind(this, credentials))
.then(function(transactions) {
cb(null, transactions);
},
function(err) {
console.log(err);
cb(err, null);
});
},
}
How am I supposed to be calling this Restangular POST from the AngularJS controller? It should not be returning undefined.
Since you are getting the response from the server side, it means that your server side code and the angular service code is working just fine. :)
The only possibility I can see is that I is wrong with the application of .then() block is that insted of two parameters(i.e., response and err) lets try with only one parameter.
Something like following :
$scope.addUser = function (chaseUser) {
Accounts.addChaseUser(userToSubmit).then(function (response) {
if(response.status == 'error'){
$log.debug('Got error in the response');
}else{
$log.debug('SUCCESS');
}
});
};
I have used .then(function(data)) with only one parameter. That is the only thing I could find :)
Incase you still don't see it, you are missing a few returns in your functions.
addUser: function (req, res) {
return PlaidService.provideCredentialsToMFA(
// ... your code ...
);
},
provideCredentialsToMFA should return the promise
provideCredentialsToMFA: function (credentials, cb) {
return plaidClient.addConnectUser(
// ... Your code ...
);
}
EDIT:
simplifying the working code looks something like this. Notice there are no returns and only callbacks are used:
findChargeById: function (req, res) {
fetchCharge(someParams, someCallBack);
}
fetchCharge: function (chargeId, cb) {
stripe.charges.retrieve(chargeId, anotherCallBack);
}
Your code looks like this. It's similar but the $scope.addUser expects something returned and doesn't use a callback
addUser: function (req, res) {
provideCredentialsToMFA(someParams, someCallBack);
// addUser returns nothing
}
provideCredentialsToMFA: function (credentials, cb) {
plaidClient.addConnectUser(someParams, someCallBack);
// provideCredentialsToMFA returns nothing and it seems plaidClient.addConnectUser returns nothing too
}
$scope.addUser = function (userInfo) {
// Here is the difference with your 'then' call. Accounts.addUser doesn't return anything and takes 2 params
Accounts.addUser(userInfo).then(someCallBack);
};

Backbone.js model.save() - proper server response

Something seems to be wrong, either my server response or my save function.
In neither case success nor error function of model.save() gets invoked.
My server response:
exports.updateBusinessBannerAd = function(req, res) {
// update banner ad
db.insert(req.body, req.body._id, function(err, data) {
if (err) {
console.log('Update business banner ad: ' + err.message + ' ' + err['status-code']);
res.send(err['status-code'], { header: 'Update banner ad', message: err.message, type: 'error'});
}
else {
res.send(200);
}
});
};
And here my client code:
saveBannerAd: function(self) {
self.model.id = self.model.attributes._id;
self.model.save({
success: function(model, res) {
utils.growl( 'Banner Ad', 'has been updated!', 'info');
self.resetHandler();
},
error: function(model, res) {
console.log(res);
utils.growl(res.header, res.message, res.type);
return;
}
});
},
What am I missing?
Okay, adding { id: self.model.get('id') } as first argument to model.save() fixed my issue.
In this thread
someone suggested setting 'null' as first argument serves as placeholder, but my experience is that this will invoke the error function.

Resources