-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Problems stemming from late loopback.context initialization #1651
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
Comments
Adding something small to this - I've taken to using "initial:before": {
"loopback#context": {
"params": { "enableHttpContext": true }
},
"loopback#token": {}
} I'm happy to update the "Using current context" documentation to recommend this, but it's not clear to me whether this is inline with the intentions for when context and token should be used/available. |
Hey @doublemarked, thank you for writing down this detailed analysis!
The way I see "current context", it should contain transport-agnostic data only, so that your clients can easily switch between transports when needed (REST, JSON-RPC, WebSocket, etc.) By including HTTP OTOH, I do realise that multi-transport remains just an theoretical concept not used in practice (so far).
The current implementation is optimised to make it easy to setup a full app with as few lines of code as possible: var app = loopback();
app.use(loopback.rest());
// bang, everything is included Of course, if your middleware setup is more complex than the above, then yes, you should initialise the context middleware very early. I am proposing the following change: modify the project template in loopback workspace (source) and add explicit configuration of context & token middleware. {
"initial": {
"compression": {},
"cors": { /* ... */ },
"loopback#context": {
"params": { "enableHttpContext": false }
}
},
// ...
"auth": {
"loopback#token": {},
},
// ...
} Thoughts? |
Thank you @bajtos for the detailed response! It helps a lot to hear the rationale for some of the code design. I understand much more clearly now the motivations. I find your proposed solution perfect. A small connected question - should the default configuration for |
Based on this conversation and where it all began (#337), here's what I understand:
@doublemarked - If i have understood it all correctly then I'm inclined to agree with you that its duplicate work and can probably can be removed. But even if it was left there it wouldn't do any immediate harm ... although the next time changes need to happen, and its not someone in the "know" then that developer will tear their hair out trying to figure out the significance of the same config in two places and probably wish for better cleanup :) Disclaimer: @bajtos could still come in from an omniscient angle and inform us that there is an arcane code workflow that is not covered when middleware is moved up the phase chain so take my |
I am proposing to go even one step further and prevent the REST adapter from adding any context middleware at all by setting {
"remoting": {
"context": false,
"rest": {
"normalizeHttpPath": false,
"xml": false
},
// etc.
}
} Here is a use case (user story?) to show the benefit of such approach. As a LoopBack user, I start by scaffolding a new loopback application via A quick search shows that And here is the catch: if Thoughts? |
I agree with your use-case, but it highlights what I feel is more directly the problem - there are two locations for configuring the same module, and now both would be present in the default configuration files. And what's more, one of them is additive ( I'm having trouble coming up with an easy solution to suggest that fits our stated objectives. However - we might consider having a set of "default middleware configuration" that is enabled in absence of explicit configuration. Currently we do have middleware defaults, but these are handled module by module, like the default stuff enabled in Instead, there should simply be an internalized version of This may produce some backwards compatibility issues that would prevent this from being viable in the near term. I have not yet thought through that aspect. Thoughts? |
That's a good point, I understand how confusing this is for new LoopBack users.
I see two possibly independent changes in your proposal.
1) No default context configuration in
|
Hi there - sorry for the delayed response here.
Great! This will be a big improvement. I love it. It also removes the boiler plate code from Q: should
I'm with you. Thanks for this reminder of the design objectives.
Yep, sounds good. Am I correct in seeing that the additive changes will be primarily to the template, without substantial code changes? Tangential question: Your config sample has |
I think it's not necessary, as loopback.rest always handles the request (e.g. by sending 404 for unknown paths). At least in the default configuration.
I hope so :)
I'm glad you have asked. My original idea was that this new option can serve as a shortcut for This becomes important when loopback.rest adds a new dependent middleware in the future, as it will simplify upgrade of existing applications. Because existing apps will be unaware of that new dependency (it won't be disabled in rest config and configured in middleware config), the auto-loading mechanism will kick in and ensure that the rest transport has all dependencies loaded. If we were using "autoloadDependencies" to disable all dependent middleware, then we would end up with an application that tells rest middleware to not load the new dependency, but at the same time the app won't configure the new dependency explicitly. |
So, I spent some time tonight poking around at this topic. I've now done my homework on how As I understand it - we extract all middlewares that have been implicitly loaded via Specifically, the following middlewares will now be configured by default in Question/Concern: The strong-remoting
Question/Concern: The Question/Concern: While the Tangential Question: Why are some 3rd party middlewares ( Setting aside the above questions, here is a summary of the changes as I currently see them:
Looking forward to hearing back from you. |
Hi @doublemarked, sorry for a late reply, your thorough analysis requires more time to digest it.
In general, I think we should upstream any customizations of 3rd party middleware.
"tolerate empty json" - this may be rather controversial. We are returning an empty object when the body is empty, however I can imagine that
This is a performance optimisation, I hope it should be accepted to CORS without much resistance.
Can we rework RestAdapter to load the configuration both from remotes config and RestAdapter options? IMO, RestAdapter options specified in middleware.json should override remotes config.
I am not an expert on CORS, but I would expect that multiple invocations of CORS middleware would result in a more strict policy being applied. In which case multiple invocations remain a performance problem only. Which is a minor issue IMO, because the solution is quick & easy. Thoughts?
Other middleware (
Only middleware that is provided via However, note that we actually do include few more middleware in LoopBack, see loopback's server/middleware.
Sounds good 👍 I think RestAdapter's customization of JSON & CORS need to be upstreamed as step 0. |
Hey @bajtos - my turn to apologize. I'm sorry, it's been quite a long delay here on my side. However - as is probably apparent, the size of this has ballooned a good bit (now stretching into three projects), and has started to exceed the bandwidth I have available to get involved, particularly as we shift more into less familiar territory (strong-remoting, etc.). I've been holding out, hoping to dig deeper here, but it's been six weeks ;) That said, I want to continue the discussion, which I hope may be valuable. Comments below.
Sounds like a reasonable solution (config driven), though it may cause unexpected changes in behavior for people depending on the current functionality. However I agree that burying controversial exceptions like this is undesirable.
That's my preference as well. It looks like @digitalsadhu committed something to fix this in October, immediately after you wrote your message. May not be a coincidence ;)
You may be right, though I am wary of placing so much hope/expectation in 3rd party modules the that they behave properly/efficiently when added twice. IIRC the objective of enabling things here (in RestAdapter) is to allow for configuration-less setup, and there may eventually be a scenario where there's a piece of middleware that can be meaningfully added twice in other use cases but not in ours, preventing us from depending on the vendor to short-circuit. But you're right, this is not the case with the ones I cited.
Agreed! |
FWIW, we are discussing that favicon should be removed: #1827 |
Hey @doublemarked, thank you for the update. I agree this has grown much more that we anticipated in the beginning. I'll try to revisit this issue and our discussion in order to come up with some smallish incremental steps that are beginner-friendly. However, I can't promise any timeframe, it may take few weeks :( |
Ouch, those few weeks to come back to this issue grew into a year :( Some parts of this discussion is no longer relevant:
The remaining parts (moving strong-remoting configuration from @doublemarked what's your opinion? Are you still keen to contribute some of the changes described above? Or should we closing this issue? Any other idea? |
@bajtos I agree that this has grown stale and that much of it is no longer relevant. I'm in favor of closing it out. Thanks for following up on it, regardless of the delay :) |
The
loopback.context
middleware is enabled by default via theloopback.rest
middleware. With this comes some rudimentary configuration, includingenableHttpContext
. The default initialization is great, but the delayed mechanism by which its initialized can produce unexpected results.Specifically - functionality outlined in the sample code of the context documentation (https://docs.strongloop.com/display/LB/Using+current+context) produces a scenario where it's necessary to initialize
loopback.context
earlier. An excerpt:This explicit initialization of
loopback.context
andloopback.token
is necessary, otherwise the middleware (which necessarily runs beforeloopback.rest
) will not have access to the context. Afterwards, because the context was initialized early, we lose support for the configuration loading present in theloopback.rest
init process. To more accurately load the context we would need to either hard-code theenableHttpContext
value here, or perform our own config loading. The same holds true for token.All of this is relatively easy to resolve, provided the developer is willing to spend some hours digging through loopback code trying to figure out why
enableHttpContext
doesn't work. Anyhow.Related Questions:
loopback.context
initialized so late? It is quite useful for middleware to have access to it in order to pass things on to the API. Should it perhaps be initialized very early?enableHttpContext
being configurable, anyways? Isn't this a reasonable default to include in the context?A low-impact recommendation: Provided I have interpreted the above correctly, should the sample code in the documentation perhaps be changed to explicitly include a value for
enableHttpContext
? Like this,The text was updated successfully, but these errors were encountered: