meteor / meteor-feature-requests

A tracker for Meteor issues that are requests for new functionality, not bugs.
Other
89 stars 3 forks source link

Allow Accounts API hooks to return Promises #345

Open laddi opened 5 years ago

laddi commented 5 years ago

Currently all the Accounts API hooks are synchronous, such as Accounts.onLogin(data => ...) or Accounts.validateLoginAttempt(data => ...), and require that all included actions are run synchronously, otherwise they will "fire" after the login process has already finished. Accounts.onLogin is particularly effective for loading related data/resources for the user logging in but in most cases it would be beneficial to have that data loaded while Meteor.loggingIn() is still true.

It would be beneficial to allow async/await on these functions, i.e. Accounts.onLogin(async data => await ...) and the Accounts API would then know when the callback was a Promise and await it accordingly. The way to bypass this limitation today is to use someMethod.await(), which is less than ideal.

The same goes for related APIs, of course, like OAuth.

CaptainN commented 5 years ago

You can use my package to wrap that: https://github.com/CaptainN/async-proxy

You can import getProxy, and then make Accounts a proxy object:

import { getProxy } from 'meteor/npdev:async-proxy'
import { Accounts } from 'meteor/accounts-base'
const AccountsProxy = getProxy(Accounts)

async function myFunc () {
  try {
    const result = await AccountsProxy.loginWithPassword('username', 'password')
    // do stuff with the result - redirect to authenticated route or something
  } catch (error) {
    console.error(error)
    // do stuff with the error - display "bad password" to user, etc.
  }
}

getProxy takes any object with methods that have a standard node.js callback method signature (callback function as the last argument, which takes (error, result) arguments). It does almost no error prevention though, so you have to know what you are doing - it just forwards your values, and sets up the Promise.

I use this for error processing in my login forms, and after login routing. But I mostly consider the state of login as an an action (in Flux terminology) and then let the reactive Meteor.user() and Meteor.userId() reflow the login state through my hierarchy using withTracker.

(I just realized getProxy isn't mentioned in the readme - will fix)

laddi commented 5 years ago

Cool, didn't know about this package. I still feel that this should be part of Meteor core functionality, though, but I'll take a look at it to see if it fits my needs. On first glance it seems to focus more on the client side whereas I'm thinking mainly for server side but maybe I'm wrong...

CaptainN commented 5 years ago

You are right - my package is more of a client side package. I'm never quite sure how to apply async/await on the server because of Fibers...

I had thought of importing the Meteor Promise package in async-proxy to allow it to work server side with Fibers, but I haven't tried that since I don't really use it server side.

CaptainN commented 5 years ago

A quick read on how async/await works with promises on the server suggests async-proxy may work as is on the server https://blog.meteor.com/using-promises-and-async-await-in-meteor-8f6f4a04f998