0

I know Javascript but very new to NodeJS. I want to reuse http request anywhere in my code, outside of server.js. Please take a look:

server.js

    var http = require('http');
    var mongodb = require('./db');
    var settings = require('./settings');
    var oauth = require('./oauth');

    //start mongodb connection
    mongodb.connect(function(error){
        if (error) console.error(error);
        else {
            //set db as mongodb client
            var db = mongodb.use();
            //start http server
            http.createServer(function(request,response){
                //set POST body
                request.body = '';
                request.on('error',function(error){
                    console.error(error);
                    response.statusCode = 404;
                    response.end();
                }).on('data',function(chunk){
                    request.body += chunk;
                }).on('end',function(){
                    //database and http server ready, start logic
                    //Now I want to "require" a file here, such as test.js and call "request.headers" to work
                });
            }).listen(settings.httpPort,function(){
                console.log('Server listening on '+settings.httpServer+':'+settings.httpPort);
            });
        }
    });

And now I want to require test.js which do the following thing
test.js

    console.log(request.headers);

Note: I don't want to use any framework like Express. I want to write my own things from scratch. Please help me, thank you so much.

1

1 Answer 1

1

If I understand correctly, the problem seems to be this: You want to access the result of an asynchronous function (the HTTP request) in other modules. However, Node's require() is synchronous; there is no asynchronous require(). There are a few solutions to this, none of which will be unfamiliar if you know JavaScript.

The simplest solution is to wrap your server.js module in a function that takes a callback. Then, call the callback once the request is available, like so:

// server.js
'use strict';

// ...

module.exports = function(callback) {

  // ...

  http.createServer((req, res) => {
    req.body = '';

    // Call end with error on error
    req.on('error', err => res.end(err));

    // Append chunks to body
    req.on('data', chunk => req.body += chunk);

    // Call callback here
    req.on('end', err => {
      // Call with error as first argument on error
      if (err) callback(err);
      // Call with request as second argument on success
      else callback(null, req);
    });

  }).listen(/*...*/);
  // ...
};

And in your test.js file:

// test.js
'use strict';

const server = require('./server');

// Do something with the request here.
server((err, req) => {
  if (err) console.error(err);
  else console.log(req.headers);
});

There is a problem with this approach. Every time you want to access the request, your server function will run all over again. What if you want to run the server once and then have access to the request as many times as you want?

Consider using Node's events module for this. In your server.js file, you can export an EventEmitter instance instead of a function. Emit appropriate events in that module, and then you can add listeners in any other module that needs access to the request. Your server.js file will look something like this:

// server.js
'use strict';

const EventEmitter = require('events');
const emitter = new EventEmitter();

// ...

http.createServer((req, res) => {
  req.body = '';
  req.on('error', err => res.end(err));
  req.on('data', chunk => req.body += chunk);

  // Emit events here:
  req.on('end', err => {
    // Emit 'error' event on error.
    if (err) emitter.emit('error', err);
    // Emit 'data' event on success.
    else emitter.emit('data', req);
  });
}).listen(/*...*/);

// ...

module.exports = emitter;

And in your test.js file:

// test.js
'use strict';

const server = require('./server');

// Do something on error event.
server.on('error', console.error);

// Do something on data event.
server.on('data', req => {
  console.log(req.headers);
});
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you McMath, the second solution is very good. Now I wonder this, from inside server.js I will require test.js and from test.js I require server.js. Will it cause an unending loop or something?
@ShanRuan It won't cause an infinite loop. Node can handle cyclic dependencies. But it could easily cause other problems if you don't have a very good grasp of how modules are loaded in Node. I would suggest trying to rethink your code to eliminate cyclic dependencies if you can. Otherwise, whether it will cause problems will depend on your code. You might consider searching for other questions on this site that might help you, or perhaps asking a new question entirely.
Hi McMath. You said it could cause other problems. Can you please give me some examples about the problems? I'm a PHP headed for years, so there are many things new for me in NodeJS. Thank you so much.
@ShanRuan For example, you might find that the module you are requiring has not yet been defined. To know when that is likely to happen requires a good understanding of how modules are loaded, which is why I suggested it might be best to try to avoid cyclic dependencies for now. In any case, this topic is too big for the comments section. For more detail, I suggest you search Google or Stack Overflow for "cyclic dependencies in node", and if you still have questions, you can open a new question on that topic.
Thank you for your kindness

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.