newbie question is following:
I'm having a hard time to get the EventEmitter to work. I already considered the documentation and several best-practive tutorials like this one: https://code.tutsplus.com/tutorials/managing-the-asynchronous-nature-of-nodejs--net-36183
The problem is, that within the user.js (Class) this.emit() hits nothing. userRoutes.js doesn't trigger any user.on(), and I really don't know why..
Any suggestions are appreciated. Hints for better structuring also. My goals are centralized endpoints (well-readable) and reusing the code for every module (like user or products/orders) within different modules, e.g. calling to update an order out of the user-endpoint.
So, let's assume, you have your node.js-Server with a module configuration, router and several classes, like this:
/server.js
global.__base = __dirname + "/";
var server = require("http").createServer();
var routes = require("./v2");
var initialize = require(global.__base + "config");
var app = initialize.globalModules();
app.use('/api/v2', routes);
app.listen('8090');
/config.js
var db;
module.exports = {
globalModules: function() {
// load the global modules
var app = require("express")();
var bodyParser = require("body-parser");
//setUp app
app.use(bodyParser.json());
return app;
},
db: function() {
var mysql = require('mysql');
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'node_docx'
});
db.connect(function(err) {
if (err) throw err;
});
return db;
}
};
/v2/index.js (routes)
var userRoutes = require('./userRoutes');
var routes = require('express').Router();
routes.use("/user", userRoutes);
//routes.use("/product", productRoutes);
//routes.use("/order", orderRoutes);
//...
routes.use('*', function(req, res) {
res.status(404).send({code: 404, message: 'ERR', data: "Unknown target."});
});
module.exports = routes;
/v2/userRoutes.js
var User = require("./routes/user.js");
var user = new User();
var route = require('express').Router();
route.get("/", function(req, res) {
user.on('error', function(err) {
res.status(400).send({code: 900, message: 'ERR', data: err});
});
user.on('failure', function() {
res.status(404).send({code: 901, message: 'ERR', data: "User not found!"});
});
user.on('success', function(result) {
res.status(200).send({code: 200, message: 'OK', data: result});
});
user.getAll();
});
module.exports = route;
/v2/routes/user.js
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var initialize = require(global.__base + "/config");
var db = initialize.db();
function User() {
EventEmitter.call(this); //edit: added, but has not solved the problem
var self = this; //solved it!
function _checkForErrors(error, rows, reason) {
if (error) {
self.emit('error', error);
return true;
}
if (rows.length < 1) {
self.emit('failure', reason);
return true;
}
return false;
}
function _getData(error, rows) {
if (_checkForErrors(error, rows)) {
return false;
} else {
self.emit('success', rows);
}
}
function getAll() {
db.query("SELECT * FROM patient", _getData);
}
this.getAll = getAll;
}
util.inherits(User, EventEmitter);
module.exports = User;
It's quite simple, you forgot EventEmiter.call(this) in function User.
function User() {
EventEmitter.call(this);
var self = this;
function _checkForErrors(error, rows, reason) {
if (error) {
self.emit('error', error);
return true;
}
if (rows.length < 1) {
self.emit('failure', reason);
return true;
}
return false;
}
function _getData(error, rows) {
if (_checkForErrors(error, rows)) {
return false;
} else {
self.emit('success', rows);
}
}
function getAll() {
db.query("SELECT * FROM patient", _getData);
}
this.getAll = getAll;
}
Related
services/user.js
var AWS = require('aws-sdk'),
amazonCognitoIdentity = require('amazon-cognito-identity-js');
module.exports = function (cognitoUserPool) {
var ddb = new AWS.DynamoDB();
var UserService = function (cognitoUserPool) {
this.userPool = new amazonCognitoIdentity.CognitoUserPool({
UserPoolId : cognitoUserPool.user_pool_id,
ClientId : cognitoUserPool.client_id // App Client id
});
}
UserService.prototype.login = function(email, password) {
// do stuff
}
return UserService;
}
routes/user.js
var express = require('express'),
UserService = require('../services/user');
module.exports = function(serverCredentials){
const router = express.Router();
const userServiceInstance = new UserService(serverCredentials['cognito-user-pool']);
router.post('/auth', function(req, res) {
var email = req.body.email;
var password = req.body.password;
if (email && password) {
userServiceInstance.login(email, password).then(function(result) {
// do stuff
}, function(err) {
// do stuff
})
}
});
}
Result:
TypeError: userServiceInstance.login is not a function
Why?
This is my database class which I want to exist only once because I want only one connection for the application and not multiple connections.
var mysql = require('mysql');
var fs = require("fs");
var eventEmitter = require("./events.js");
function Database() {
this.connection;
this.poolCluster;
var host;
var username;
var password;
var db;
var config;
var clusterConfig = {
removeNodeErrorCount: 5,
restoreNodeTimeout: 1000,
defaultSelector: 'ORDER'
};
var poolConfig = {
acquireTimeout: 10000,
waitForConnections: false,
connectionLimit: 10,
queueLimit: 0
};
this.connect = function() {
this.connection = mysql.createConnection({
host: config.mysqlHost,
user: config.mysqlUsername,
password: config.mysqlPassword,
database: config.mysqlDb
});
this.connection.connect(function(err) {
if(err) {
console.error("Connection couldn't established at " + config.mysqlHost + " (user: " + config.mysqlUsername + ")"
+ "\nError: " + err);
return;
}
console.log("Connected to mysql server at " + config.mysqlHost + " (user: " + config.mysqlUsername + ")");
this.poolCluster = mysql.createPoolCluster(clusterConfig);
this.poolCluster.add("APP", poolConfig);
this.poolCluster.add("ACCOUNTS", poolConfig);
this.poolCluster.add("GAME", poolConfig);
console.log("Created Connection Clusters\n- APP\n- ACCOUNTs \n- GAME");
eventEmitter.emit("MysqlConnectionReady");
});
};
this.getMainConnection = function() {
return this.connection;
};
this.getAppConnection = function() {
this.poolCluster.getConnection("APP", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
this.getAccountsConnection = function() {
this.poolCluster.getConnection("ACCOUNTS", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
this.getGameConnection = function() {
this.poolCluster.getConnection("GAME", 'ORDER', function(err, connection) {
if(err) throw err;
return connection;
});
};
fs.readFile(process.cwd() + "/config.json", 'utf8', function(err, data) {
if(err) throw err;
config = JSON.parse(data);
this.connect();
});
}
module.exports = Database:
In my code I set module.exports = Database;
When I want to use Database in another file its undefined. I want to use this in another file and I want to use only instance of that because I want only one connection for the app Im running.
But if I use require('./Database.js'j; and use the var it returns undefined
To use the pseudo-classical OOP approach, where you define a Class as a JS function (as shown in your snippet), you would instantiate an object with the new keyword.
Instead of module.exports = Database, try creating the instance and exporting that as the module, like this:
const db = new Database();
module.exports = db
I'm looking to change requestHandler.value to 5 for my functional styled tests.
When running the suite, creating 1000 documents in the db is not really an option, so is it possible to change it's value programmatically before running the suite and then reset it afterwards? I can create 5 documents in db before the test to work with.
Of coarse I can stub countDocumentsInDb() in unit tests to return what I need, but I've simplified logic below for the sake of the question.
app.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var requestHandler = require('./lib/requestHandler.js');
var PORT = 4000;
app.route('/validate')
.get(function(req, res) {
requestHandler.process(req, res);
});
if (!module.parent) {
server.listen(PORT, function(err) {
if (err) {
return;
}
});
}
module.exports = app;
requestHandler.js:
var requestHandler = {
value: 1000,
process: function(req, res) {
numberOfDocumentsInDb = countDocumentsInDb();
if (numberOfDocumentsInDb === this.value) {
res.send(true);
} else {
res.send(false);
}
}
};
module.exports = requestHandler;
FVT style test ..
var Promise = require('promise');
var request = require('supertest');
var chai = require('chai');
chai.should();
var server = require('../../app.js');
describe('app.js', function() {
describe('/validate', function() {
it('should return true if number of documents in db matches pre-defined value', function(done) {
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
});
});
});
You can play with the require.cache, that will allow you to modify the values of requestHandler.
Is just an example I hope you get the idea.
- In the before each modify the require cache and set your test values
-In the after each set back the original values
-Please notice that the const server = require('./app.js'); is inside the test, so it will take the cache vales
e.g.
describe('test with cache', function(){
require('./requestHandler');
let originalValues;
beforeEach(function() {
originalValues = require.cache[ require.resolve('./requestHandler') ].exports;
require.cache[ require.resolve('./requestHandler') ].exports = {
value:5,
process: function(req, res) {
//other stuff
}
};
});
afterEach(function() {
require.cache[ require.resolve('./requestHandler') ].exports = originalValues;
});
it('should pass', function(){
const server = require('./app.js');
var fvtPromise = new Promise(function(fulfill) {
request(server)
.get('/validate')
.expect(200)
.end(function(err, res) {
if (err) {
throw err;
}
res.body.should.equal(true);
fulfill(null);
});
});
fvtPromise.done(function() {
done();
});
expect(true).to.be.true;
});
});
var express = require('express');
var search = express.Router();
search.get('/', function(req, res, next) {
console.log('1');
dbCall(function(error, result) {
if (error) {
res.status(404).json();
} else {
res.json(result);
}
});
console.log('last');
next();
});
var dbCall = function(callback) {
var couchbase = require('couchbase');
var cluster = new couchbase.Cluster('couchbase://127.0.0.1');
var bucket = cluster.openBucket('default');
var doc;
var ViewQuery = couchbase.ViewQuery;
var query = ViewQuery.from('dev_test', 'allData');
bucket.query(query, function(err, viewResults) {
if (err) {
callback(err, null);
} else {
console.log('inqueryCall');
var results = viewResults;
callback(null, results);
console.log(results);
}
});
};
module.exports = search;
Here's the error that I get is :
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
Can someone please explain the issue here(not just the solution)?
I've added console.log and the issue here is that the couchbase call to async
Remove next() call, that is causing this error. next() is used in middleware to pass the flow to next middleware or endpoint/route
search.get('/', function(req, res, next) {
dbCall(function(error, result) {
if (error) {
res.status(404).json();
} else {
res.json(result);
}
});
});
I'm wondering why req.session.username is undefined in the tag >>>DOESNT WORK<<< while it does work in the tag >>>THIS DOES WORK<<< . I brought in req as an argument to my module but it seems I'm supposed to do something else? The /ajax route is accessed via a ajax call and it does set the session variable in >>>THIS DOES WORK<<<
//index.js file
var express = require('express');
var router = express.Router();
var app = express();
var functions = require('../public/javascripts/functions.js');
router.post('/ajax', function(req, res , next){
var username = req.param("username");
var password = req.param("password");
var operation = req.param("operation");
else if (operation === "validate")
{
async.series([
function()
{
functions.validate(username, password, req);
}
], function(err,result)
{
if (err)
return console.log(err);
console.log(result);
});
//req.session.username = "yaryar"; >>>THIS DOES WORK<<<
}
var strings = ["rad", "bla", "ska"]
console.log('body: ' + JSON.stringify(req.body));
console.log("AJAX RECEIVED");
res.send(strings);
});
module.exports = router;
functions.js file:
module.exports = {
validate: function(username, password, req) {
var url = 'mongodb://localhost';
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
MongoClient.connect(url, function(err, db)
{
assert.equal(null, err);
console.log("Connected correctly to server.");
var cursor = db.collection('users').find({username : username});
cursor.each(function(err,doc,req)
{
assert.equal(err, null);
if (doc != null)
{
console.log("user found: " + doc.username);
req.session.username = "ttyy"; // >>>DOESNT WORK<<<
return true
}
else
{
console.log("user not found");
return false;
}
});
//db.close();
});
}
};
you're overwriting req by doing cursor.each(function(err,doc,req) change it to cursor.each(function(err,doc,arr) and it will work