17

I am writing a web app in node.js. Now every processing on the server is always in the context of a session which is either retrieved or created at the very first stage when the request hits the server. After this the execution flows through multiple modules and callbacks within them. What I am struggling with is in creating a programming pattern so that at any point in the code the session object is available without the programmer requiring it to pass it as an argument in each function call.

If all of the code was in one single file I could have had a closure but if there are function calls to other modules in other files how do I program so that the session object is available in the called function without passing it as an argument. I feel there should be some link between the two functions in the two files but how to arrange that is where I am getting stuck.

In general I would like to say there is always a execution context which could be a session or a network request whose processing is spread across multiple files and the execution context object is to be made available at all points. There can actually be multiple use cases like having one Log object for each network request or one Log object per session. And the plumbing required to make this work should be fitted sideways without the application programmer bothering about it. He just knows that that execution context is available at all places.

I think it should fairly common problem faced by everyone so please give me some ideas.

Following is the problem

MainServer.js


  app = require('express').createServer();
  app_module1 = require('AppModule1');
  var session = get_session();
  app.get('/my/page', app_module1.func1);

AppModule1.js

  app_module2 = require('AppModule2');
  exports.func1 = function(req,res){

     //  I want to know which the session context this code is running for

     app_module2.func2(req,res);

   }

AppModule2.js

   exports.func2 = function(req,res){

    // I want to know where the session context in which this code is running

    }
Raks
  • 1,723
  • 3
  • 18
  • 26

4 Answers4

9

You can achieve this using Domains -- a new node 0.8 feature. The idea is to run each request in it's own domain, providing a space for per-request data. You can get to the current request's domain without having to pass it all over via process.domain.

Here is an example of getting it setup to work with express: How to use Node.js 0.8.x domains with express?

Note that domains in general are somewhat experimental and process.domain in particular is undocumented (though apparently not going away in 0.8 and there is some discussion on making it permanent). I suggest following their recommendation and adding an app-specific property to process.domain.data.

https://github.com/joyent/node/issues/3733

https://groups.google.com/d/msg/nodejs-dev/gBpJeQr0fWM/-y7fzzRMYBcJ

Community
  • 1
  • 1
Matt Smith
  • 164
  • 1
  • 5
0

Nodetime is a profiling tool that does internally what you're trying to do. It provides a function that instruments your code in such a way that calls resulting from a particular HTTP request are associated with that request. For example, it understands how much time a request spent in Mongo, Redis or MySQL. Take a look at the video on the site to see what I mean http://vimeo.com/39524802.

The library adds probes to various modules. However, I have not been able to see how exactly the context (url) is passed between them. Hopefully someone can figure this out and post an explanation.

EDIT: Sorry, I think this was a red-herring. Nodetime is using the stack trace to associate calls with one another. The results it presents are aggregates across potentially many calls to the same URL, so this is not a solution for OP's problem.

Aneil Mallavarapu
  • 3,485
  • 5
  • 37
  • 41
0

Since you are using Express, you can get session attached to every request. The implementation is following:

var express = require('express');
var app = express.createServer();
app.configure('development', function() {
  app.use(express.cookieParser());
  app.use(express.session({secret: 'foo', key: 'express.sid'}));
});

Then upon every request, you can access session like this:

app.get('/your/path', function(req, res) {
  console.log(req.session);
});

I assume you want to have some kind of unique identifier for every session so that you can trace its context. SessionID can be found in the 'express.sid' cookie that we are setting for each session.

app.get('/your/path', function(req, res) {
  console.log(req.cookies['express.sid']);
});

So basically, you don't have to do anything else but add cookie parser and enable sessions for your express app and then when you pass the request to these functions, you can recognize the session ID. You MUST pass the request though, you cannot build a system where it just knows the session because you are writing a server and session is available upon request.

instinctious
  • 694
  • 3
  • 10
  • 2
    Well you are using req as a carrier for passing execution context data along. That is not what I am looking for. On a more general level, I am looking to replace arguments in functions altogether and having constant names across files which when used points to the correct object. So if I do req.something anywhere across files, it would be correct req object as it would have passed on automatically – Raks Mar 29 '12 at 14:44
  • Well, instead of writing the whole system for that, you should use https://github.com/dwbutler/express-on-railway – instinctious Mar 29 '12 at 15:09
  • 2
    @Raks here the problem is you are confusing the concept of per-file or global with per-request. In node, and in event based networking in general, the request is the context. Otherwise, there is no way to distinguish what session (an artificial construct) you are referencing and you get races. Node is neither PHP nor Rails, the entire interpreter survives between requests as does the global scope. – Timothy Meade Mar 30 '12 at 02:03
0

What express does, and the common practice for building an http stack on node.js is use http middleware to "enhance" or add functionality to the request and response objects coming into the callback from your server. It's very simple and straight-forward.

module.exports = function(req, res, next) {
    req.session = require('my-session-lib');
    next(); 
};

req and res are automatically passed into your handler, and from their you'll need to keep them available to the appropriate layers of your architecture. In your example, it's available like so:

AppModule2.js

exports.func2 = function(req,res){

    // I want to know where the session context in which this code is running
    req.session; // <== right here

}
Brad Harris
  • 1,520
  • 9
  • 12
  • 3
    You'll note that you're passing in the request and response here. The OP was about not needing to pass that stuff into every module. – Will Shaver Jul 10 '12 at 22:22