Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I overload the functionality of app.listen in expressjs

I've been trying to create (basically) a factory function that configures and builds an expressjs server for a dozen smaller specialized servers I have. For part of this I want to augment the listen function.

I would like to know the best way to go about this. I'm also looking for a reusable design choice here.

Server is created normally:

var httpServer = express();
    ...

Because of the way express is designed (Not sure if I am correct) I cannot access a {whatever}.prototype.listen. So I have come up with two approaches.

Using an additional variable in the current scope:

 var oldListen = httpServer.listen;
 httpServer.listen = function(callback){
    ...
    oldListen.call(httpServer, options.port, options.host, function(){
       ...
       if ( typeof callback == 'function' ) callback();                    
    });
 };

Which works and is fairly straight forward but then I have a variable hoisting wart. I also have a closure solution, but I think it may be too obtuse to be practical:

httpServer.listen = (function(superListen){
   return function(callback){
      ...
      superListen.call(httpServer, options.port, options.host, function(){
         ...               
         if ( typeof callback == 'function' ) callback();
      });
   };                                             
})(httpServer.listen);

Both examples are part of the factory context and I am intentionally reducing the arguments passed to the function.

Any help would be appreciated.

like image 477
Jotham Avatar asked Sep 02 '14 02:09

Jotham


People also ask

What is listen in ExpressJS?

listen() function which Binds and listens for connections on the specified host and port. Like 5. Express.js | app.set() Function.

What does the listen () function do in Node js?

listen() method creates a listener on the specified port or path.

How do I handle multiple sessions in Node js?

Here, since sess is global, the session won't work for multiple users as the server will create the same session for all the users. This can be solved by using what is called a session store. We have to store every session in the store so that each one will belong to only a single user.

What does the app listen method do?

The app. listen() method binds itself with the specified host and port to bind and listen for any connections. If the port is not defined or 0, an arbitrary unused port will be assigned by the operating system that is mainly used for automated tasks like testing, etc.


2 Answers

If you insist on "overloading", make sure you implement the original footprint (such is the nature of overloading). Express listen is just an alias to node's internal http listen method:

server.listen(port, [host], [backlog], [callback]);

UPDATE: Express even suggests using node's server API for custom implementations: http://expressjs.com/4x/api.html#app.listen

Otherwise, you should create your own custom listen method which would be defined like:

httpServer.myCustomListen = function (callback) {
    httpServer.listen.call(httpServer, options.port, options.host, callback);
}

The second option is your best bet, but in order for it to work, you must extend the express library. Express is open source and hosted on Github. Fork it and modify it as you please. Periodically pull in new updates so you stay up-to-date with the core library. I do this all the time with node modules.

There are two benefits from doing it this way:

  1. You have complete control to customize the code however you see fit while staying up to date with the code written by the original authors.

  2. If you find a bug or build a cool feature, you can submit a pull request to benefit the community at large.

You would first fork the repository, then grab the URL for your fork, clone it, and then add a reference to the original "upstream" repo:

git clone [url_to your_fork]
cd express
git remote add upstream [email protected]:strongloop/express.git

Then you can push changes to your own repo (git push). If you want to get updates from the original repo, you can pull from the upstream repo: git pull upstream master.

If you want to add your custom fork of express as an npm module for a project, you would use the following:

npm install git://github.com/[your_user_name]/express.git --save
like image 154
Ryan Wheale Avatar answered Oct 20 '22 14:10

Ryan Wheale


As Victor's answer pointed out, express's prototype is in express/lib/application.js. That file is used to build express and is exported via the application namespace in express/lib/express.js. Therefore, the .listen function can be referenced using express.appliction.listen.

One can use this method then: (similar to Victor's method)

var express = require('express');

express.application._listen = express.application.listen;
express.application.listen = function(callback) {
  return this._listen(options.port, options.host, callback);
};

One can also use Lo-dash's _.wrap function if you don't want to store the base function in a variable yourself. It would look something like this:

var express = require('express');
var _ = require('lodash');

express.application.listen = _.wrap(express.application.listen, function(listenFn) {
  return listenFn(options.port, options.host, callback); // Called with the same this
};

However, using these methods would run into the problems that you mentioned in your question (variable hoisting, creating an extra variable). To solve this, I would usually create my own subclass of express.application and replace the .listen function in that subclass and tell express to use that subclass instead. Due to express's current structure, however, you cannot replace express.application with your own subclass without overriding the express() function itself.

Hence, what I would do is to take over express.application.listen completely since it is only 2 lines. It is rather simple!

var express = require('express');
var http = require('http');

express.application.listen = function(callback) {
  return http.createServer(this).listen(options.port, options.host, callback);
};

You can even make an https option!

var express = require('express');
var http = require('http');
var https = require('https');

express.application.listen = function(callback) {
  return (options.https ? http.createServer(this) : https.createServer({ ... }, this))
          .listen(options.port, options.host, callback);
};

Note: One of the other answers mentions forking express and modifying it. I would have a tough time justifying that for such a small function.

like image 28
tyronegcarter Avatar answered Oct 20 '22 14:10

tyronegcarter