-
Notifications
You must be signed in to change notification settings - Fork 15.8k
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
Support custom router #2431
Support custom router #2431
Conversation
The answer to this has always been "no" because it adds more API surface for absolutely no reason: just add all your stuff on your custom router and then |
As an extension to this problem, think of this: Express releases 4.15 and adds a new method to the router for a cool feature. A proxy is added to Replacing the router is not a thing that makes sense, especially when you just |
I see your point. Basically if my patch was landed, it would mean that every time we added a new method to router, we would have to increase the major version, as we are breaking compatibility with custom routers. That would be really bad. However, in my case, the custom router is inheriting from
I disagree. Firstly, I don't want to tell all LoopBack users that they can no longer use Secondly, and this is more important, my custom router implementation runs routes registered via app.use(handler1);
app.phase('init').use(handler2); // custom LoopBack API
app.use(handler3);
app.phase('final').use(handler4); // custom LoopBack API
// order of execution:
// handler2, handler1, handler3, handler4 I cannot add my custom router in the main middleware chain, as there is no (reasonably easy) way how to figure out what is the correct position for the custom router. I understand your concerns about making router customization a public feature. Hopefully my explanation clarified my needs and you understand them too. Can we come up with a way that will satisfy both of us? You don't want to make this a public API, I don't want to maintain a copy of How about making it a private undocumented thing intended for expert users only? Basically I need express application to read the |
Refactor `app.lazyrouter` to fetch the `Router` ctor function from a property that can be changed by express users. NOTE: Customizing the default router is not an officially supported usage. It's up to you to fix any issues you may encounter in such case.
98ef7cf
to
7f37bf4
Compare
@dougwilson I have updated the PR to match my proposal above. |
I would say you are approaching the problem from the wrong direction: you shouldn't be returning an
I 100% want to. I pined you on IRC to talk, but didn't get an answer back yet. If we need to setup a time to discuss, let me know, but the current proposal is too broken for Express as it is right now, but I can definitely work with you to get a solution. Express was designed in a specific way is all. |
Let me extend that a little bit: I want to return an derived instance of
Thanks, I appreciate that. Not all OSS projects/maintainers share the same approach.
I'll try to catch you up tomorrow. Or we can discus asynchronously here. In the mean time, I'll revisit my current solution to see if there is a way how to simplify it and use a different mechanism for integrating it with express. |
Hopefully! Framework collaboration has been the basis of our
Yes, it would be better to think of exporting loopback, rather than express with loopback additions. This doesn't mean it will become incompatible with express-based modules. Your framework will still have all of the express-exposed API available in it, if you like. This honestly sounds like a request for I think all of the express maintainers firmly believe the future is in a componentized "framework" that can be used to build these express-module-compatible frameworks. You may be interested in a talk I did on this recently; we'd love to build this with anyone and everyone.
|
@Fishrock123 Your proposal sounds good and it will be a great solution in the long term. My problem is that I need a short-term solution that works with express 4.x as it is today. A small patch, not a major change... |
@bajtos It would be preferable to export loopback as a router, that will put you the most forward in terms of being able to easily adopt pillarjs in the future. :) I should note that by "in the future" we mean at most 3 months. I'll let @dougwilson advise, but if you are currently monkey-patching things, the best option may be to continue to do so until pillar comes out in full force. The patched things are unlikely to change in severe ways during express 4, I think. Any help on pillar would probably help accelerate it greatly, which sounds like it is desirable. |
i'd rather extract all the prototype methods attached to node's request and response objects into its own repo and let people make their own framework with their own routers and such. |
I'm going to accept a variant of this patch, even though the way you are injecting the router is a terrible idea and I guarantee is going to lead to people reporting bugs to loopback. |
When strongloop/loopback#757 becomes more mature and is getting ready for release, I'll schedule a Express 4.x minor release to correspond with it. This will also give us time to make sure this is the right solution to your issue before merging it is now, and then perhaps you realizing there is a better way and we're left with something in Express we didn't particularly want. Does that make sense? |
P.S. you can do this in Express 5.0 as an officially-supported thing: var express = require('express')
var PromisedRouter = require('router-as-promised')
module.exports = function createApplication() {
var app = express()
var router = null
// this is only necessary if you need to be lazy-initialized
Object.defineProperty(app, 'router', {
get: function getrouter() {
if (router === null) {
router = new PromisedRouter({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
})
}
return router
}
})
return app
} |
Makes sense. I was thinking about your feedback in the evening and I came up with an idea for a different implementation, one that does not involve a custom router. I'll try it and see if it's better than the current proposal.
That's much better. FWIW, I still have a minor concern about that code, as you have to manually build a list of router options via multiple IMHO, it would be nice to expose a function to build the default router settings object. // in the app
Object.defineProperty(app, 'router', {
get: function getrouter() {
if (router === null) {
router = new PromisedRouter(this.buildRouterConfig())
}
return router
}
})
// in express
app.buildRouterConfig = function() {
return {
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
}
} Just a food for thoughts, this discussion does not belong to this PR. |
Right, but you're assuming your custom router even has "strict" and "case-sensitive" settings at all, and it would preclude you from being able to let people control settings that are specific to your router using
but why not? it all seems relevant to me :) |
In my case, the router is extending You can always control the router-specific settings, as you can add more stuff to the config object created by express, or don't use the default config object at all. // extend
var config = this.buildRouterConfig()
config.myCustomOpt = app.get('my custom opt')
router = new PromisedRouter(config)
// replace
var config = {
myCustomOpt: app.get('my custom opt')
};
router = new PromisedRouter(config); |
I had a nice discussion with @dougwilson about the different approaches for customising the router behaviour. He wrote down a simple proof-of-concept that works with the current express version and does not depend on too many internals - see his gist. Using some of his ideas, I was able to modify the LoopBack code so that it does not create any custom Router implementation - see app.lazyrouter in my branch. As far as I am concerned, this issue can be closed. Thank you all for your help. |
Add a new parameter to
express
function to provide a customRouter
constructor.
Example:
Rationale
This patch make it easier to experiment with different router implementations, as it enables developers (express users) to swap out the default Router implementation and replace it with their own.
Discussion points
An existing workaround is to copy and edit
app.lazyrouter
to call a different Router constructor. This is very brittle as the copied version must be manually synchronized with any changes made in express.Adding the first parameter to
express()
may be seen as controversial. Frankly, I don't really care about the API. I am happy to rework the PR to a different API as long as it allows me to change the Router ctor used byapp.lazyrouter
.Example:
@dougwilson @jonathanong Thoughts?