Extend View class in Express on Node.js - node.js

I'd like to override the View class in the Express framework, used in Node.js. I want to augment the lookup method, but I can't see a way to do this without altering the Express and App modules. I'd favour deriving from the Express framework, but I can't figure out a neat way to do this.
Any ideas?
Thanks

It seems to me you should be able to:
var View = require('express/lib/view');
// Keep reference to original lookup method
var _lookup = View.prototype.lookup;
// Override lookup method
View.prototype.lookup = function (path) {
// Your implementation here
};
Update:
Run this as a demonstration:
var View = require('express/lib/view');
var _lookup = View.prototype.lookup;
var express = require('express');
View.prototype.lookup = function (path) {
console.log('LOOKUP!!! ' + path);
return _lookup.call(this, path);
};
var app = express();
app.get('/', function (req, res) {
res.render('foo.jade');
});
app.listen(3000);
Run
node app & sleep 1 && curl localhost:3000
I hope this will demonstrate the viability of this way of overriding a method.

It depends on which version of Express you are using.
You can easily augment the view lookup code only if your app is using Express prior to version 3
Since Express 3.0 that's not doable anymore.
You can check one of my old related answers for sample code:
Multiple View paths on Node.js + Express

Related

Please explain the basic server setup code of Express.js

In this code snippet:
Const express = require('express')
Const app = express();
/*Typeof express = function
Typeof app = function*/
app.get()
My question is: if app is a function then how can we use a dot operator with it to call get function, and if we are creating a object of function express then why didn't we use new keyword to create an object.
Secondly, module.exports exports the literals in object format then why we are getting typeof express here a function.
If I am wrong anywhere, please correct me.
In JavaScript functions are objects, so this is valid:
function x() {
console.log("this is x()");
}
x.y = function() {
console.log("this is x.y()");
}
x();
x.y();
Express and other JavaScript tools use this feature extensively.
If you're used to other languages where functions are just functions and not objects themselves this will seem extraordinarily strange.

Can I pass variable to required file?

In express, I'm trying to move my minification to a requierd file:
app.js:
var app = express();
var minify = require("./minify.js");
In that file I try to set my template engine.
minify.js:
var app = express();
app.engine('html', mustacheExpress());
Later when I try to use to use the rendering engine in app.js, I get the error that no template-engine is set. It works if I run it all in the same file. I think the problem is that I declare the app-variable twice. How can I pass the app-variable into minify.js?
The problem is that you define new app variable, and you currently instantiate brand new express instance by calling express().
What you need to do is start using functions so that you can pass params (there are other methods too, but this is one that will work for you):
// app.js
var app = express();
var minify = require('./minify'); // don't include .js!
minify(app); // CALL the function that minify.js exports, passing params
// minify.js
module.exports = function(app) {
// because app comes as a parameter, it's the very same you've created in app.js
app.engine('html', mustacheExpress());
}
Again, there are many different methods and maybe proper approaches, depending on what you want to do, but this will do the job in your case. Read more about NodeJS and it's require system.
You can pass 'app' from app.js to your minify by using function in your module like Andrey said. You can do it like this too for example :
minify.js
module.exports = {
setAppEngine : function(app) {
app.engine( [...] );
}
}
And calling it like this in your app.js:
app.js
var app = express();
var minify = require("./minify.js").setAppEngine(app);
This solution is very useful because you can set and call others methods in minify.js. For example, you can do with the same code in minify.js:
app.js
var app = express();
var minify = require("./minify.js");
minify.setAppEngine(app);

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.
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:
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.
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 git#github.com: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
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.
You should be able to easily overload the express listen function. You can access it in the following Object path: express.application.listen
So, you can implement something like this:
var express = require('express');
express.application.baseListen = express.application.listen;
express.application.listen = function(port) {
console.log('Port is: ' + port);
this.baseListen(port);
};
The implementation of the listen function is in the following path under the express module folder: node_modules\express\lib\application.js
Bind and listen for connections on the given host and port. This method is identical to node's http.Server#listen().
var express = require('express');
var app = express();
app.listen(3000);
The app returned by express() is in fact a JavaScript Function, designed to be passed to node's HTTP servers as a callback to handle requests. This allows you to provide both HTTP and HTTPS versions of your app with the same codebase easily, as the app does not inherit from these (it is simply a callback):
var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
The app.listen() method is a convenience method for the following (if you wish to use HTTPS or provide both, use the technique above):
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
Reference:http://expressjs.com/api.html
Hope This helps.

Hierarchical routing with plain Express.js

I’m implementing a RESTful API using Node and Express. When it comes to routing, currently it looks like this:
var cat = new CatModel();
var dog = new DogModel();
app.route('/cats').get(cat.index);
app.route('/cats/:id').get(cat.show).post(cat.new).put(cat.update);
app.route('/dogs').get(dog.index);
app.route('/dogs/:id').get(dog.show).post(dog.new).put(dog.update);
I don’t like this for two reasons:
Both cat and dog models are instantiated whether I need them or not.
I have to repeat /cats and /dogs for every path schema
I’d love to have something like this (not working, of course):
app.route('/cats', function(req, res)
{
var cat = new CatModel();
this.route('/').get(cat.index);
this.route('/:id').get(cat.show).post(cat.new).put(cat.update);
});
app.route('/dogs', function(req, res)
{
var dog = new DogModel();
this.route('/').get(dog.index);
this.route('/:id').get(dog.show).post(dog.new).put(dog.update);
});
Is there a clean way in modern Express without any further modules (like express-namespace)? I could go for separate routers for each model and assigning them with app.use('/cats', catRouter). However, what if I have more than one hierarchy level like '/tools/hammers/:id'? I would then have routers within routers within routers, which seems like overkill to me.
I would then have routers within routers within routers, which seems like overkill to me.
Perhaps, but that is the built-in method of prefixing -- to app.use() a Router().
var cats = express.Router();
app.use('/cats', cats);
cats.route('/').get(cat.index);
cats.route('/:id').get(cat.show).post(cat.new).put(cat.update);
// ...
And, to have one Router .use() another to define multiple depths:
var tools = express.Router();
app.use('/tools', tools);
var hammers = express.Router();
tools.use('/hammers', hammers);
// effectively: '/tools/hammers/:id'
hammers.route('/:id').get(...);
Though, to be closer to your 2nd snippet, you can define a custom method:
var express = require('express');
express.application.prefix = express.Router.prefix = function (path, configure) {
var router = express.Router();
this.use(path, router);
configure(router);
return router;
};
var app = express();
app.prefix('/cats', function (cats) {
cats.route('/').get(cat.index);
cats.route('/:id').get(cat.show).post(cat.new).put(cat.update);
});
app.prefix('/dogs', ...);
app.prefix('/tools', function (tools) {
tools.prefix('/hammers', function (hammers) {
hammers.route('/:id').get(...);
});
});
Check out the new Router in Express 4. It sounds exactly what you're looking for.

How to Make a Call to Koa.js App Instance for Unit Tests

I don't know how I'd term this maybe 'static call to a koa router'? Does that seem like the right wordage here for what I'm really trying to accomplish if you were to talk about it technically?
Anyway, I'm using koa-router and I'm coding unit tests (not integration tests). So I do not want to invoke .listen() on my koa app because of that reason...it would create an http server which now makes my test an integration tests.
Instead in my test I simply want to make a straight call to the app object instance and call a route and be able to return no results and check that I returned no results in the response.
How can you do that? I can't find an example and I've tried all sorts of pseudo code attemps agains the koa app object.
If you want to test the function that koa-router routes to then just perform a unit test on that function and leave the routing out of it.
To me it sounds like you've got a file such as app.js and it contains all your code. What you can do is create a router.js file to put you route bindings and a services.js file where you can put your application logic.
So for example app.js might look like:
var koa = require("koa");
var app = module.exports = koa();
var router = require('./router.js');
app.use(router.unsecured.middleware());
app.listen(3000);
And router.js might look like:
var router = require("koa-router");
var service = require("./services.js");
var unsecured = module.exports.unsecured = new router();
unsecured.post('/account/signin', service.signinUser);
unsecured.post('/account/register', service.registerUser);
And services.js might look like:
module.exports.signinUser = function*(signinDetails) {
// contains your application signin logic
};
module.exports.registerUser = function*(registerDetails) {
// contains your application register logic
};
So in this manner you can individually test services.js. I don't see any value in individually testing router.js since it is so trivial. As #Dan Pantry shows you can test routing as part of an integration test using supertest.
Edit:
So this is a little experimental test I was playing around with to test that the routing is correct. I'm using mocha as the test runner and the code example I posted in my original code.
// standard library
var assert = require("assert");
// in app objects
var router = require('./router.js');
var service = require('./service.js');
describe("routing tests", function() {
it("test register routing, POST", function*(done) {
// arrange
var unsecured = router.unsecured;
var path = '/account/register';
var httpMethod = 'POST';
var expected = service.register.toString();
var actual;
// act
for (var i = 0; i < unsecured.stack.length; i++)
{
var pathMatch = unsecured.stack[i].path === path;
var methodMatch = unsecured.stack[i].methods.indexOf(httpMethod) >= 0;
if (pathMatch && methodMatch)
{
actual = unsecured.stack[i].middleware.toString();
break;
}
}
// assert
try {
assert.equal(expected, actual);
done();
} catch(err) {
done(err);
}
});
});
There is probably a neater way of doing this (and a more modular way for testing multiple paths) but as I said this is just a basic example to verify the routing is calling the correct service. What I'm doing is delving into the koa-router object to verify what path is bound to what service code depending on the HTTP method (e.g. POST, GET, etc).
If you have your routing and your services in modules this test completely avoids dealing with the main koa app. Although technically this test spans multiple units (the routing and the service code) so it would technically be an integration test but it does mean you don't go near app.listen() which is what you didn't want to call in your tests.

Resources