node.js and async module error - javascript

I am getting an undefined variable in my code and not sure what the error in my code is:
I get client as undefined when I call getClient...
I have a soap client creation singleton and I have:
var mySingleton = (function() {
var soap = require('soap');
var async = require('async');
var instance;
var client;
function init() {
var url = "http://172.31.19.39/MgmtServer.wsdl";
var endPoint = "https://172.31.19.39:9088";
var options = {};
options.endpoint = endPoint;
async.series([
function(callback) {
soap.createClient(url, options, function (err, result){
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback();
});
}
],
function(err) {
if (err)
return next(err);
});
return {
getClient : function() {
console.log("I will give you the client");
**return client;**
},
publicProperty : "I am also public",
};
};
return {
getInstance : function() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
module.exports = mySingleton;
so my consumer is :
var soapC = mySingleton.getInstance();
var mySoapClient = soapC.getClient();
I get mySingleton.client is undefined.
Why?

Sure there are better solutions than this one, but it shows you that it can be implemented easier (without async, without singleton):
var soap = require('soap');
var client;
var url = "http://172.31.19.39/MgmtServer.wsdl";
var options = {
endpoint: "https://172.31.19.39:9088"
};
module.exports = {
getClient: function (callback) {
if (client) {
callback(null, client);
return;
}
soap.createClient(url, options, function (err, result) {
if (err) {
callback(err);
return;
}
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback(null, client);
});
},
publicProperty: "I am also public"
};
And when using the client:
// using the client
var mySoapServer = require('./path/to/above/code.js');
mySoapServer.getClient(function (err, client) {
if (err) { /* to error handling and return */ }
client.someRequestMethod(myEnvelope, function (err, response) {
// ...
});
});
There might be a problem when your Soap-Clients gets into trouble (there is no logic to reconnect in case of error). For this you could have a look at the source code of Redis-Client, MySQL-Client, MongoDB-Client, ...
Edit
Some comments on the different aproaches:
The Singleton-pattern is not needed here. Node will execute this JS file only once and further requires get only a reference to the exports. There is no need to create an IIFE scope - the variables won't be visible outside, only the exports.
Programming in Node.js is (besides some special cases) an all-async way. If not done consequently, it just doesn't work or fails/succeeds only if you have good/bad luck.
Error handling looks very much like a lot of boilerplate, but it's necessary in most cases.

Related

Callback is not a function -manage asynchronous call Node js

I am reading files from ftp using the code below.
var JSFtp = require("jsftp");
var config = require('./config.json');
var FtpService = function () {};
// Connect to FTP
var Ftp = new JSFtp({
host: config.ftp.host,
port: config.ftp.port,
user: config.ftp.user,
pass: config.ftp.pass
});
FtpService.prototype.getFTPDirectoryFiles = function (callback) {
Ftp.list(config.ftp.FilePath, function(err, res) {
if(err){
console.log('File Listing Failed', err);
callback(null,err);
return;
}
else{
console.log(res);
callback(null,res);
}
});
};
FtpService.prototype.closeFtp = function () {
console.log('Disconnect to FTP');
};
module.exports = new FtpService();
Now i include this ftp service js file in my index.js as
var ftp = require('./ftpservice.js');
ftpfiles = ftp.getFTPDirectoryFiles();
console.log(ftpfiles);
getFTPDirectoryFiles returns the list of file. But if i call it via index.js i get undefined ftpfiles. This is because of the asynchronous nature of node js.
so i thought of adding callback but
I am getting the error Callback is not defined in function FtpService.prototype.getFTPDirectoryFiles
In this line:
ftpfiles = ftp.getFTPDirectoryFiles()
you are not passing the callback that that function requires and are trying to use a return value that the function does not return.
You need to do something like this:
var ftp = require('./ftpservice.js');
ftp.getFTPDirectoryFiles(function(err, ftpfiles) {
if (err) {
console.log(err);
} else {
console.log(ftpfiles);
}
});
You need to pass a callbackfunction in your function getFTPDirectoryFiles();
var ftp = require('./ftpservice.js');
var ftpFiles;
function setFtpFiles(err, res) {
if (err) throw err;
ftpFiles = res; // to use "ftpFiles" variable later
console.log(res);
}
ftp.getFTPDirectoryFiles(setFtpFiles);
1 Don't change args order to call callback. (replace callback(null,err); and callback(null,res); by callback(err,res);)
2 You need define a specifc function (your callaback) an give it to ftp.getFTPDirectoryFiles().
var JSFtp = require("jsftp");
var config = require('./config.json');
var FtpService = function () {};
// Connect to FTP
var Ftp = new JSFtp({
host: config.ftp.host,
port: config.ftp.port,
user: config.ftp.user,
pass: config.ftp.pass
});
FtpService.prototype.getFTPDirectoryFiles = function (callback) {
Ftp.list(config.ftp.FilePath, function(err, res) {
if(err){
console.log('File Listing Failed', err);
callback(err, res);
return;
}
else{
console.log(res);
callback(err, res);
}
});
};
FtpService.prototype.getFTPDirectoryFilesSimplify = function (callback) {
// no console.log, but very more simple !
Ftp.list(config.ftp.FilePath, callback);
};
FtpService.prototype.closeFtp = function () {
console.log('Disconnect to FTP');
};
and then :
var ftp = require('./ftpservice.js');
ftpfiles = ftp.getFTPDirectoryFiles(function(err,res){
// do your specifc job here using err and res
});
console.log(ftpfiles);

Test and stub params in POST request

Guys how can I stub params in POST request, for example here a part of function
gridCalculator : function(req,res){
// calculation logic
var options=[];
options.dateFirstLicensed = req.param('DateFirstLicensed');
options.dateFirstInsured = req.param('DateFirstInsured');
options.claimList = req.param('ClaimList');
options.suspenList = req.param('SuspenList');
...etc
if I did this
it('grid Calculate', function (done) {
var req = {
'DateFirstLicensed' : "01-01-2010",
'DateFirstInsured': "01-01-2011",
'ClaimList': ['05-03-2012'],
'SuspenList': [{'StartDate':'05-03-2012','EndDate':'05-05-2012' }]
};
gridCalculator.gridCalculator(req,function (err, result) {
result.should.exist;
done();
});
});
I get error because I'm simply passing an object not POST request
TypeError: req.param is not a function
Two options come to mind (there are probably a lot more):
Option 1: Define the param function yourself:
it('grid Calculate', function (done) {
var params = function(param) {
switch (param) {
case 'DateFirstLicensed':
return "01-01-2010";
case 'DateFirstInsured':
... //do the same for all params
}
};
var req = {
param: params
};
gridCalculator.gridCalculator(req,function (err, result) {
result.should.exist;
done();
});
});
Option 2: Use tools like supertest to create calls to your server's endpoint.
The problem is that you don't stub the function that is used in your gridCalculator method in your test.
It should look like this:
it('grid Calculate', function (done) {
var testParams = {
'DateFirstLicensed' : "01-01-2010",
'DateFirstInsured': "01-01-2011",
'ClaimList': ['05-03-2012'],
'SuspenList': [{'StartDate':'05-03-2012','EndDate':'05-05-2012'}]
};
var req = {
param: function (paramName) {
return testParams[paramName];
}
};
gridCalculator.gridCalculator(req,function (err, result) {
result.should.exist;
done();
});
});

Multiple node.js requests

My controller is using the request package to make server-side HTTP requests to another API. My question is how can I make MULTIPLE of these requests? Here is my current code:
** UPDATED CODE **
module.exports = function (req, res) {
var context = {};
request('http://localhost:3000/api/single_project/' + req.params.id, function (err, resp1, body) {
context.first = JSON.parse(body);
request('http://localhost:3001/api/reports/' + req.params.id, function (err, resp2, body2) {
context.second = JSON.parse(body2); //this line throws 'SyntaxError: Unexpected token u' error
res.render('../views/project', context);
});
});
};
I need to make two more of those calls and send the data returned from it to my template...
Can someone help?
Thanks in advance!
function makePromise (url) {
return Promise(function(resolve, reject) {
request(url, function(err, resp, body) {
if (err) reject(err);
resolve(JSON.parse(body));
});
});
}
module.exprts = function (req, res) {
let urls = ['http://localhost:3000/api/1st',
'http://localhost:3000/api/2st',
'http://localhost:3000/api/3st'].map((url) => makePromise(url));
Promise
.all(urls)
.then(function(result) {
res.render('../views/project', {'first': result[0], 'second': result[1], 'third': result[2]});
})
.catch(function(error){
res.end(error);
});
}
You can use Promise lib in latest nodejs.
Simple solution
Nest request calls. This is how you can handle the dependency between requests. Just make sure your parameters are unique across scopes if needed.
module.exports = function (req, res) {
var context = {};
request('http://localhost:3000/api/1st', function (err, resp1, body) {
var context.first = JSON.parse(body);
request('http://localhost:3000/api/2nd', function (err, resp2, body) {
context.second = JSON.parse(body);
request('http://localhost:3000/api/3rd', function (err, resp3, body) {
context.third = JSON.parse(body);
res.render('../views/project', context);
});
});
});
};
Simplest way if you use bluebird promise library:
var Promise = require('bluebird');
var request = Promise.promisify(require('request'));
module.exports = function (req, res) {
var id = req.params.id;
var urls = [
'http://localhost:3000/api/1st/' + id,
'http://localhost:3000/api/2st/' + id,
'http://localhost:3000/api/3st/' + id
];
var allRequests = urls.map(function(url) { return request(url); });
Promise.settle(allRequests)
.map(JSON.parse)
.spread(function(json1, json2, json3) {
res.render('../views/project', { json1: json1 , json2: json2, json3: json3 });
});
});
it executes all requests even if one (or more) fails

Sending images to the client with nodejs and socket.io

with the following code I'm able to send an Image to the client with socket.io, but I want also to send the size as a second argument. I would like to understand why the argument "size" is getting always undefined when I try to pass it to the socket.emit function. socket.emit('firstChunkSent', data, size). Can you pls fix it ?
var io = require('../server').io
io.sockets.on('connection', function (socket) {
socket.on('imageRequest', function () {
getTheNewImage(function(data,size){
socket.emit('firstChunkSent', data, size)
});
});
});
function getTheNewImage(callback){
var filename = 'image.gif';
var base64FileSize = fs.stat(filename,function(err,stats){
if (err) { throw err; }
return stats.size
});
var readable = fs.createReadStream(filename, { encoding: 'base64' });
readable.on('readable', function() {
var getImageData = function(){
while (null !== (base64ImageData = readable.read())) {
return base64ImageData
}
}
callback(getImageData(),base64FileSize)
});
readable.on('end', function() {
console.log('there will be no more data.')
});
readable.on('error', function(err) {
console.log('here is the error: '+err)
readable.end(err);
});
return stats.size
Need to use the callback
function getTheNewImage(callback){
var filename = 'image.gif';
var base64FileSize = fs.stat(filename,function(err,stats){
if (err) return callback(new Error(err));
callback(null, stats.size)
});
getTheNewImage(function(data,size)
First param will be the error, not data

This scope lost with inheritance

Here is the example code, two files and "classes".
CRUD class with defined methods, the problem occurs with this.modelName, as I set the routes the this context changes with this code:
The question is how, to get the same scope under the CRUD where you have defined the modelName ?
server.get('/users/:id', UserRoutes.find);
Code:
var db = require('../models');
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
}
CRUD.prototype = {
ping: function (req, res, next) {
res.json(200, { works: 1 });
},
list: function (req, res, next) {
// FAILS BECAUSE the modelName is undefined
console.log(this);
db[this.modelName].findAll()
.success(function (object) {
res.json(200, object);
})
.fail(function (error) {
res.json(500, { msg: error });
});
}
};
module.exports = CRUD;
UserRoutes class:
var CRUD = require('../utils/CRUD'),
util = require('util');
var UserModel = function() {
UserModel.super_.apply(this, arguments);
};
util.inherits(UserModel, CRUD);
var userRoutes = new UserModel('User');
module.exports = userRoutes;
I assume that you are using userRoutes.list as a handler somewhere else, i.e. the context changes. In that case this should be a simple solution:
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
this.list = CRUD.prototype.list.bind(this);
}
Note that you won't be able to access "the other this" with that solution (this will be permamently bound to CRUD instance, no matter how .list is called).
The other option is to turn list into a function generator (which is pretty much the same what .bind does, except you can still use this from the other context):
CRUD.prototype = {
// some code
list: function() {
var that = this;
return function (req, res, next) {
console.log(that);
db[that.modelName].findAll()
.success(function (object) {
res.json(200, object);
})
.fail(function (error) {
res.json(500, { msg: error });
});
}
}
};
and then use userRoutes.list() as a handler.
This sort of thing is generally fixed by stowing the right this into _this. In your list function this is the function object, which doesn't have a modelName object.
var _this;
function CRUD(modelName) {
this.modelName = modelName;
this.db = db;
_this = this // <---------------
}
....
// call the _this in the outer scope
db[_this.modelName]

Categories