I am trying to set up logging for the native mongo driver for node. I've got the following snippet set up as a demonstration for what I am trying to do. Unfortunately nothing is being emitted on the console. Any ideas?
var express = require('express') ;
var app = express();
var http = require('http');
var mongod = require('mongodb');
var server_conf = new mongod.Server('localhost', 27017, {auto_reconnect:true});
//dummy logger
var logger = {
error:function(message, object) {console.log('anything')},
log:function(message, object) {console.log('anything')},
debug:function(message, object) {console.log('anything')}}
var db_container = {db: new mongod.Db('test', server_conf,
{w:1,journal:true, native_parser:true, logger: logger})}
app.use(express.bodyParser());
app.use(app.router);
db_container.db.open(function(err, index_info){
if(err) throw err;
var testcol = db_container.db.collection('testcol');
app.get('/', function(request, res){
testcol.insert({hello:"moto"}, function(err,doc){
if(err){
throw err;
}
testcol.find({}).toArray(function(err,docs){
res.send(docs);
});
});
});
http.createServer(app).listen(3000, function () {
console.log('Express server listening on port ' + '3000');
});
});
Replicated below is: a copy of the answer to this question I posted on the node-mongodb-native google group
After looking at the most recent version of the code (commit 0fd78b3278da8deac980cb876fcb2bf72eaafb79) it looks like logging isn't really implemented yet.
First some ground rules: If you create a server config object (http://mongodb.github.io/node-mongodb-native/api-generated/server.html?highlight=server#Server) and set the logger object there that's ok. If you create a Db() object and set a logger in its options then it will override any logger you have set its server config. If you create a MongoClient() object this is equivalent to new Db('test', serverOptions, options) so you can set your logger object in either serverOptions or options. I'm not going to cover MongoClient.Connect and what happens there because I don't care to look over that portion of the code.
I could only find usage of the logger object happening in connection.js where it's revealed that you actually need a few additional properties to get logging working.
i.e line 69
if(this.logger != null && this.logger.doDebug){
this.logger.debug("opened connection", this.socketOptions);
}
or line 307
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
There are many more doDebug/doError property lookups in connection.js that require logging to work. There is a very minimal amount of logging happening from the looks of it but if you want to enable it you need to set the doError/doLog/doDebug properties on your logger as well. I actually haven't tested this out since I don't have the proper setup here but from looking over the code this seems to be the case.
Related
it is a naive question.
Say you have a config file storing all you need for making a connection to your db.
If you are reading asynchronously, is the connection done in the callback?
fs.readFile(pathToConfigFile, function (err, data){ createConnection(data);});
Does it look ugly, suspicious and bit dangerous, doesn't it?
(This is an example, but I'd like to hear some opinions about it, if and why it is worng doing that and so on)
In my case I am using mongoose, I query the db on the schema object (i.e. User.find()...) so I simply get null results because the connection doesn't happen synchronously I guess.
Thank you very much
(here is my app-structure)
app.js
db.js (read the config file and make the connection)
config.json (info of db and others)
user.js (model for users)
home.js (query all the users and list them on .get '/')
It's ok to so sync operations during app start up. However, do not do any sync stuff once the app has started, especially while handling requests.
Your app should be configured to start IF the database connectivity was successful.
// set up your app
var express = require('express')
var app = express()
....
// set up database connectiveity
var db = mongoose.connection;
db.on('error', function() {
console.log('DB connectivity error')
process.exit()
});
db.once('open', function() {
// start your app now
app.listen()
});
create config.json like this:
config.json
module.exports = {
dbUrl:"mongodb://localhost/testDB",
serverPort: 9999
// add you other config key here
}
and require config file wherever you want to use like:
var config = require("./config");
console(config, config.severPort)
Suggestion: Use config module. It will read your config file as per the environment or default config file
Scenario
Using node_redis to build a simple Redis Pubish Subscribe (chat) example: https://github.com/nelsonic/hapi-socketio-redis-chat-example (with Hapi.js and Socket.io)
We have created a node module redis_connection.js in our project ( see: http://git.io/vqaos ) to instantiate the Redis connection because we don't want to be repeating the code which connects (to RedisCloud) multiple times:
var redis = require('redis');
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname,
{no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")[1]);
module.exports = redisClient;
Which we then use like this:
var redisClient = require('./redis_connection.js');
// Confirm we are able to connect to RedisCloud:
redisClient.set('redis', 'working', redisClient.print);
redisClient.get('redis', function (err, reply) {
console.log('RedisCLOUD is ' +reply.toString());
});
This works fine for normal GET/SET operations with Redis,
but when we try to instantiate multiple connections to Redis (e.g: one to publish, another to subscribe and a third just to GET/SET keys/values) we get an error:
Issue
We are seeing the following error:
Error: Connection in subscriber mode, only subscriber commands may be used
What are we doing wrong?
Full code at the point where we see this issue: http://git.io/vqa6y
Note
We tried to dig through existing SO Q/A on this, e.g:
Publish subscribe with nodejs and redis(node_redis)
Redis publish/subscribe: see what channels are currently subscribed to
how to use the redis publish/subscribe
but did not find a solution that exactly matched our situation...
(any suggestions/help much appreciated!)
Not tested, but too long for a comment.
Try to define another redis connection module, one for your regular usage and a second one solely for your pubsub subscriptions usage.
Add a redis_pubsub_connection.js to your project:
var redis = require('redis');
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisPubSubClient = redis.createClient(redisURL.port, redisURL.hostname,
{no_ready_check: true});
redisPubSubClient.auth(redisURL.auth.split(":")[1]);
module.exports = redisPubSubClient;
And change your publish.js require statement to:
var redis = require('./redis_pubsub_connection'); // RedisCloud
redis-connection node.js module
In the interest of keeping this re-useable across our projects we wrote a (mini) node.js module to initialize Redis connections: https://github.com/dwyl/redis-connection
The code is simple and tested and takes care of authentication if required.
(not copy-pasting the module here to avoid duplication)
see: https://github.com/dwyl/redis-connection/blob/master/index.js
Usage:
Install from NPM
npm install redis-connection --save
Use in your script
var redisClient = require('redis-connection')();
redisClient.set('hello', 'world');
redisClient.get('hello', function (err, reply) {
console.log('hello', reply.toString()); // hello world
});
Publish Subscribe
var redisClient = require('redis-connection')(); // Publisher
var redisSub = require('redis-connection')('subscriber');
redisSub.subscribe("chat:messages:latest", "chat:people:new");
For a working example see: https://github.com/dwyl/hapi-socketio-redis-chat-example
The advantage is that we can re-use the same redisClient across multiple files in the same project without creating new connections (the single or pub/sub connection is cached and re-used)
Credit: We borrowed ideas from several places so have up-voted all the answers. But ultimately we wrote a slightly different solution so we have shared it with everyone on NPM/GitHub. Thanks again everyone!
If you want to supply regular connection and a sub one and you want to ensure you only have one of each across the application than you could use a combination of the two solutions that includes the notion of a singleton, something like this:
var subConnection, con;
var createConnection = module.exports.createConnection = function(){
var redis = require('redis');
var url = require('url'); var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname, {no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")
return redisClient;
}
module.exports.getSubConnection = function(){
if (!subConnection)
subConnection = createConnection();
return subConnection
}
module.exports.getConnection = function(){
if (!con)
con = createConnection();
return con
}
}
Repeat for the oher two connection types and call it like
var con = require('./redis_connection.js').getConnection();
The problem is that your redis client creation code is being cached by requires so you reuse the same connection again and again. Instead of returning the connection in your redis_connection module, you could return a function:
module.exports = function(){
var redis = require('redis');
var url = require('url'); var redisURL = url.parse(process.env.REDISCLOUD_URL);
var redisClient = redis.createClient(redisURL.port, redisURL.hostname, {no_ready_check: true});
redisClient.auth(redisURL.auth.split(":")
return redisClient;
}
And then call it like so:
var redisClient = require('./redis_connection.js')();
Coming from a non Node background, my first instinct is to define my service as such
MyService.js
module.exports = new function(dbConnection)
{
// service uses the db
}
Now, I want one open db connection per request, so I define in middleware:
res.locals.db = openDbConnection();
And in some consuming Express api code:
api.js
var MyService = require(./services/MyService')
...
router.get('/foo/:id?', function (req, res) {
var service = new MyService(res.locals.db);
});
Now, being that Node's preferred method of dependency injection is via the require(...) statement, it seems that I shouldn't be using the constructor of MyService for injection of the db.
So let's say I want to have
var db = require('db');
at the top of MyService and then use somehow like db.current....but how would I tie the db to the current res.locals object now that db is a module itself? What's a recommended way of handling this kind of thin in Node?
Updated Answer: 05/02/15
If you want to attach a DB connection to each request object, then use that connection in your service, the connection will have to be passed to myService some how. The example below shows one way of doing that. If we try to use db.current or something to that effect, we'll be storing state in our DB module. In my experience, that will lead to trouble.
Alternatively, I lay out the approach I've used (and still use) in this previous answer. What this means for this example is the following:
// api.js
var MyService = require(./services/MyService')
...
router.get('/foo/:id?', function (req, res) {
MyService.performTask(req.params.id);
});
// MyService.js
var db = require('db');
module.exports = {
performTask: function(id)
{
var connection = db.getOpenConnection();
// Do whatever you want with the connection.
}
}
With this approach, we've decoupled the DB module from the api/app/router modules and only the module that actually uses it will know it exists.
Previous Answer: 05/01/15
What you're talking about could be done using an express middleware. Here's what it might look like:
var db = require('db');
// Attach a DB connection to each request coming in
router.use(req, res, next){
req.locals.db = db.getOpenConnection();
next();
}
// Later on..
router.get('/foo/:id?', function (req, res) {
// We should now have something attached to res.locals.db!
var service = new MyService(res.locals.db);
});
I personally have never seen something like new MyService before in express applications. That doesn't mean it can't be done, but you might consider an approach like this
// router.js
var MyService = require('MyService');
router.get('/foo/:id?', function (req, res) {
MyService.foo(res.locals.db);
});
// MyService.js
module.exports.foo(connection){
// I have a connection!
}
I know this has been discussed a couple of times. Anyway, I feel like all the provided solutions don't (perfectly) fit to my requirement(s). I have the following code:
router.js:
------------------
var Router = function(app, resourceName, controller) {
//Create
app.post('/api/' + resourceName, function(req, res) {
console.log('Incoming request: ' + resourceName + ' (POST)');
controller.create(req, res);
});
};
module.exports = Router;
As you can see this is a very "generic" router. It can be instantiated for example in the server like this:
var app = express();
var userController = ...
var userRouter = new Router(app, 'Users', userController);
So I don't have to write a file per resource but I just have one generic router.
I would like to test my generic router but I see some problems:
How to "inject" the app? I could create an instance of Express (var app = express();) but I think a mock would be better (as this is a unit test, not an integration test!). What's the best way to get an appropriate mock?
What exactly should I test? As far as I see my router itself (without integration) isn't doing anything else but console output (not worth to test) and a call of a function (controller.create(req, res);). How should I test if this function is called? Or is there anything else to test?
You should probably make a stub implementation of app.
What you want to test is that the constructor registers listeners on specified routes + HTTP methods. I would advise putting Sinon.js stubs into your app stub, and then in your tests check that they are called with expected arguments.
I would use jasmine.createSpyObj to mock app (and maybe controller as well).
I think you just need to test that app.post gets called with the arguments '/api/' + resourceName and controller.create, because you aren't testing that express.post works correctly or not.
Here's how I'd do those two things specifically.
I'd modify router.js a little bit to make this easier:
var Router = function(app, resourceName, controller) {
app.post('/api/' + resourceName, controller.create.bind(controller))
}
module.exports = Router;
And then the test would look like this:
describe("Router", function() {
it("should route /api to controller.create", function() {
router = require('./router');
app = jasmine.createSpyObj('application', ['post']);
controller = jasmine.createSpyObj('controller', ['create']);
router(app, 'foo', controller);
expect(app.post).toHaveBeenCalledWith('/api/foo', jasmine.any(Function));
});
});
This isn't a perfect test because it isn't actually checking that controller.create specifically is getting called. That gets a little more complicated because of the .bind() stuff.
describe("Router", function() {
it("should route /api to controller.create", function() {
router = require('./router');
app = jasmine.createSpyObj('application', ['post']);
controller = jasmine.createSpyObj('controller', ['create']);
controller.create = jasmine.createSpyObj('binder', ['bind']);
controller.create.bind.and.returnValue('bar');
router(app, 'foo', controller);
expect(controller.create.bind).toHaveBeenCalledWith(controller);
expect(app.post).toHaveBeenCalledWith('/api/foo', controller.create.bind(controller));
});
});
I'm building a Node.js proxy with the intent of handling a single POST request and redirecting the payload to two separate endpoints.
Let's say my JSON payload is:
{
"owner":"0ce856fa-f17f-11e2-9062-9b7910849bf4",
"comment":"My super cool comment!",
"photo":"0928536a-53c4-11e3-ba86-4b026f27c637"
}
I need to validate this payload on the proxy endpoint before I send it off; each of these three properties must exist, and both owner and photo must match the regex below. If they don't pass validation, I need to handle the error(s) and return a message back to the user with an appropriate error code.
I've set up a basic Node.js instance with Express and Validator like so in order to accomplish this:
var url = require('url');
var request = require('request');
var express = require('express');
var check = require('validator').check,
sanitize = require('validator').sanitize;
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.all('*', function(req, res){
if (req.method == "POST")
{
try {
check(req.body.owner, {
is: "<owner> property of type [uuid] is required"
}).is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
} catch (e) {
console.log(e);
res.json({"result":"failed","message":"Your payload didn't pass validation"});
}
}
});
app.listen(9000, function() {
console.log("Server initialized on port 9000");
});
The problem: this is all fine and dandy and works great for a single validation (in this case owner), but e on catch doesn't contain any details about the property that failed validation -- if I set up multiple checks, I'd have no idea which one failed or why.
How can I set up a series of checks and retrieve the custom message I've configured? It talks about using req.onValidationError in the Validator readme, but that looks to be front-end validation, I'm not clear how (if possible) to integrate that up with the server-side code.
try express-validator which provides errors handling like:
var errors = req.validationErrors();
Update, using express-validator:
Per #shawnzhu's suggestion, I implemented express-validator instead; it took a bit of tweaking to get it working with express+connect 3.0, but given it's handling of node-validator errors, it looks like the best way to go (validating headers notwithstanding).
var express = require('express'),
expressValidator = require('express-validator');
var app = express();
app.use(express.json());
app.use(express.urlencoded());
app.use(expressValidator());
req.checkBody("owner", "<owner> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("photo", "<photo> property of type [uuid] is required; " + req.body.owner + " is invalid.").is(uuidRegex);
req.checkBody("comment", "<comment> property can't be empty").notNull().notEmpty();
req.sanitize("comment").trim();
var errors = req.validationErrors();
if (errors)
{
res.json({"result":"failed","errors":errors});
return;
}
To get it working just with node-validator:
It was the inline message validation that was causing problems:
try {
check(req.body.owner, "<owner> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.photo, "<photo> property of type [uuid] is required").is(/\w{8}(?:-\w{4}){3}-\w{12}?/);
check(req.body.comment, "<comment> property can't be empty").notNull().notEmpty();
} catch (e) {
res.json({"result":"failed","message":e.message});
}
This does the job, and validates each property based on the criteria.