-
-
Notifications
You must be signed in to change notification settings - Fork 16.2k
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
router: add async route handler support #2809
Conversation
While the async/await feature is still highly experimental and not official, it does have preliminary support in tools like babel. There are even blog posts [1] about how to use the async/await feature with express routes. However, these posts along with issue #2789 and #2788 show that using async/await is still a bit of a manual process and not clear. This change inspects the return value of a route handler to see if it is potentially a pomise. If the return value appears to be a promise then we attach to the error handler of the promise via .catch() Now a user who is using babel can write the following without needing any wrap functions as most examples to date require. ```js app.get('/', async (req, res, next) => { let user = await User.findById(); // assuming .findById() returns a primise let org = await Org.findById(); res.json({ user: user, org: org, }); }); ``` [1] https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
/cc @dougwilson @jonathanong for feedback |
Also, this does provide benefits outside of async/await. You can just return a promise from any route handler and express will wire up |
The file you changed does not exist in Express 5, and I would assume this would be a 5.0 feature, correct? Would it be more advantageous to make the PR against the router npm module instead? |
@dougwilson actually I was targeting this for Express 4 (since it is completely backwards compatible and usable without also upgrading to v5); have not looked much into Express 5 or the router repo. |
If v4 is frozen then I am certainly up to do the change against the router repo if that is what will be used going forward. Just surfaced this based on my current usage (which is all v4). |
We know it is backwards-compatible, but including promise support with the major is much more straightforward for users to understand if they can use promises and if they can use promise-based middlewares by simply knowing it as 4 vs 5. |
One of the purposes of splitting the router to the router module is also because you can then use, say, router 2 with promises in whatever version of Express you prefer without coupling the upgrade together. |
@dougwilson gotcha, ok so I should make the PR against router or do you already have a branch that handles promise based middleware/want a different approach? |
I know there have been a few people proposing ideas, but don't remember where they all are at the moment. @blakeembrey was telling me he wanted to work on this in a Skype message the other week as well. |
trying to think of weird cases with double callbacks and when you'd ever want to |
I haven't continued working on it just yet, but the primary thing for promises to handle personally would be an automatic error handle (mostly here, but you need to handle falsy resolved promises in this PR) and upstream support (so |
+1 |
+1 |
Any progress here? Without promise support, using wrapper function is so ugly! |
@dougwilson Since this PR is backward compatible, why it can't be merged into v4? Without these few lines of code we have a LOT of pain & bugs with promises/generators in route handlers. |
I'm not always monkeypatching. |
Promise-support is technically not backward compatible - for instance, it might break anyone like @garkin who has monkey patched it. If the error from I agree it's not ideal, but additional comments aren't really going to change the reality of it. |
Also, what I'd suggest doing since development is slowed and there's a bit of a bottleneck here, is building an Express-compatible router and using that until native support arrives. It's pretty easy to build a compatible router, it only needs to conform to |
@blakeembrey Can you please point to some example/doc about usage of custom router in express? |
I bet a single thing that people really want from express 5.0 is to take a modern approach for async handling without need to finally migrate from retrograde frameworks to This is called monkey patching not because monkeys are smart. As @blakeembrey correctly noted above, you need to know what are you doing.
|
@blakeembrey there's a few issues and PR regarding support |
Can we get an update on this please? |
@defunctzombie is this ever going to get implemented? |
Not by me it isn't :) |
@dougwilson any updates on this? |
This would be great, now with node 7&8 supporting async/await - for a much cleaner code. |
Node v8 will be LTS in October so async/await is a default function, I think we should add in
This is like stopping evolution, and look at |
@p3x-robot have you seen the patch above from @garkin? It works great, use it and move on. |
Do you thing @dougwilson just simply is not interested in |
I'm going to lock this thread. The PR is failing, and has had follow up PRs on the router repo ehich express 5 uses. Please read the entire thread. |
Really, since Express 5 is based on the router module and some very nice PRs have been made there, it is best to track this in a single location to prevent cobfusion from an idling pull request. Discussions and pull requests for Express 5 (and thus promise support OOB) should ideally be done in https://github.com/pillarjs/router |
While the async/await feature is still highly experimental and not official, it does have preliminary support in tools like babel. There are even blog posts [1] about how to use the async/await feature with express routes.
However, these posts along with issue #2789 and #2788 show that using async/await is still a bit of a manual process and not clear. This change inspects the return value of a route handler to see if it is potentially a pomise. If the return value appears to be a promise then we attach to the error handler of the promise via .catch()
Now a user who is using babel can write the following without needing any wrap functions as most examples to date require.
[1] https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
Note on testing:
I have not added any tests since it would require instrumenting with babel but I can do that if the current maintainers think it would be useful. Alternatively, a fake test that just passes a promise like object to a route could simulate the same results.
Alternative implementation:
If the conditional checking is not desired in the hot path, then a wrap function could be applied upon adding the actual route versus at runtime. Additionally, that would open up the possibility of putting this behind an express setting which I didn't want to do in the hot path but maybe that would also be ok.