Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Shared route handlers within a router #35

Open
frankxw opened this issue Feb 17, 2016 · 1 comment
Open

Feature: Shared route handlers within a router #35

frankxw opened this issue Feb 17, 2016 · 1 comment

Comments

@frankxw
Copy link

frankxw commented Feb 17, 2016

Originally posted this over at expressjs #2828.

I think the new title better describes what I was going for. It's basically a convenience method if you ever have to share route handlers in router.method() calls. There were a few mentions of the issue, but for now I'm posting this for discussion.

I've got two example implementations that I had originally put together below. These were made off of express/master, but if enough people think this would be useful I can put together a PR from this repo.

(Note: the terminology is a bit confused. Originally I called this "private middleware", but then it settled in that old issue to "implicit middleware". Now I'm thinking it's easier to understand as "shared route handlers", but I'd love some input there)

App/Router .with(implicitMiddleware): see this branch
New method to register an array of shared route handlers (implicitly executed middleware). You setup Apps/Routers exactly the same, but there is a new method on instances: .with([fns]). This is much better than overloading .use because it won't confuse the current functionality and doesn't allow you to use implicit middleware with a mount-path (doesn't make sense because the route has the path, not the implicit middleware). Note: this now behaves better with declared order as @dougwilson mentioned.

Full example:

var express = require('express');
var app = express();
var middleApp = express();
var leafApp = express();

middleApp.with(function(req, res, next) {
    req.someProperty = true;
    next();
});

function sendSomeProp(req, res) {
    res.send(req.someProperty || 'not set');
}

app.get('/', sendSomeProp);
middleApp.get('/', sendSomeProp);
leafApp.get('/', sendSomeProp);

app.use('/middle', middleApp);
middleApp.use('/leaf', leafApp);

var server = app.listen(1234, function() {});

// RESULTS:
//   GET '/': 'not set'
//   GET '/middle': 'true'
//   GET '/leaf': 'not set'

Implicit Middleware as a create option: see here
This is something closer to what @blakeembrey was suggesting. Instead of some wrapper though, I put the implicit middleware in the options that get passed into the router:

var router = new Router({
  caseSensitive: false,
  implicitMiddleware: [fn1, fn2, ...]
});

I also changed the create method of an express app to take in an options object similar to Router.

Full example:

var express = require('express');
var app = express();
var middleApp = express({implicitMiddleware: [function(req, res, next) {
    req.someProperty = true;
    next();
}]});
var leafApp = express();

function sendSomeProp(req, res) {
    res.send(req.someProperty || 'not set');
}

app.get('/', sendSomeProp);
middleApp.get('/', sendSomeProp);
leafApp.get('/', sendSomeProp);

app.use('/middle', middleApp);
middleApp.use('/leaf', leafApp);

var server = app.listen(1234, function() {});

// RESULTS:
//   GET '/': 'not set'
//   GET '/middle': 'true'
//   GET '/leaf': 'not set'

Some Notes

Both of the implementations do not handle fallthrough with implicit middleware. Example:

...

middleApp.with(function(req, res, next) {
    req.someProperty = 1;
    next();
});

function sendSomeProp(req, res) {
    res.send(req.someProperty ? '' + req.someProperty : 'not set');
}

app.get('/', sendSomeProp);
middleApp.get('/', function(req, res, next) {
    req.someProperty = req.someProperty + 1;
    next();
});
middleApp.all('/', sendSomeProp);
leafApp.get('/', sendSomeProp);

...

// RESULTS:
//   GET '/': 'not set'
//   GET '/middle': '1', should be '2' but the implicit middleware was called twice
//   GET '/leaf': 'not set'

It wouldn't be hard to make it so the implicit middleware is only called once during the lifetime of a request, but I feel like this could be more confusing than just knowing the pitfalls of chaining with .all.

@mspensieri
Copy link

+1 on this feature, would love to see this make its way into the core lib as we have the exact same need

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants