-
-
Notifications
You must be signed in to change notification settings - Fork 927
Conditionally promisify all model functions #272
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
Conditionally promisify all model functions #272
Conversation
lib/handlers/authorize-handler.js
Outdated
| } | ||
|
|
||
| return Promise.try(this.model.getClient, clientId) | ||
| return Promise.try(promisify(this.model.getClient, 1), clientId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be return Promise.try(promisify(this.model.getClient, 2), [clientId, null]), as the signature of getClient is (clientId, clientSecret[, callback]). Currently promisify's callback is passed as clientSecret.
model.getClient = function getClient(clientId, clientSecret, callback) {
let client = /* get client using clientId */;
if (clientSecret) {
// oops..
}
// ...
}
This could be prevented in the model by performing a check like typeof clientSecret === 'function' but callback support should really be optional. If I decide to use promises (or throw) I shouldn't have to be aware of this edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This problem persists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, will fix.
|
@mjsalinger can you provide a concrete example of how this is not working with promises and callbacks? Closing for now, but I'll surely give it a second look if something is broken. |
|
This is critical for my app. Reopening. Will update with an example shortly. |
|
@nunofgs For example, prior to this pull request, if I create a model function as follows: and the code in the library before this PR is it would not work. Because Promise.try in the example above is expecting the function So to make this model function work with the Promise chain, it needs to be Promisified, becoming |
|
This PR still breaks |
|
|
||
| return scope; | ||
| }); | ||
| if (this.model.validateScope) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously model#validateScope was a required model function. (Promise.try throws a TypeError if the first argument isn't a function. ) This change makes validateScope optional.
If this is the desired effect there should probably be an else accepting any scope. Something like this should work:
} else {
return scope;
}Without this addition all scopes are lost, resulting in a call to model#saveToken with token.scope === undefined (see for example ClientCredentialsGrantType#saveToken).
| return this.model.saveToken(token, client, user); | ||
| return token; | ||
| }) | ||
| .then(function(token) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding additional thens and Promise.try is unnecessary.
Simply replacing the old
return this.model.saveToken(token, client, user);
with
return promisify(this.model.saveToken, 3)(token, client, user)
should be fine.
Promise.try should just be used to start a new promise chain, because it catches synchronous exceptions and rejects the returned promise. Down here we're already inside a promise handler, so synchronous exceptions are caught and passed down the chain anyways.
| return this.model.saveToken(token, client, user); | ||
| return token; | ||
| }) | ||
| .then(function(token) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding additional thens and Promise.try is unnecessary. See previous comments.
| return this.model.saveToken(token, client, user); | ||
| return token; | ||
| }) | ||
| .then(function(token) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding additional thens and Promise.try is unnecessary. See previous comments.
| return this.model.saveToken(token, client, user); | ||
| return token; | ||
| }) | ||
| .then(function(token) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding additional thens and Promise.try is unnecessary. See previous comments.
| it('should support callbacks', function() { | ||
| var model = { | ||
| getAccessToken: function() {}, | ||
| getClient: function(clientId, callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing getClient to check that the callback is always passed as third argument would catch the problem described in this comment.
getClient: function(clientId, clientSecret, callback) {
should(clientSecret).equal(null);
callback(null, { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] });
}|
I was reading the documentation of
var Promise = require('bluebird');
var promisify = require('promisify-any').use(Promise);This shouldn't be a huge issue since bluebird accepts any thenable, but this brings me to the second point.
function fn() {
throw new Error('test');
}Using promisify(fn)().catch(console.log.bind(console));Using Promise.try(fn).catch(console.log.bind(console));Using So return Promise.try(this.model.getUserFromClient, client);becomes return promisify(this.model.getUserFromClient, 1)(client);instead of return Promise.try(promisify(this.model.getUserFromClient, 1), client); |
|
I like this approach, I'll make the necessary changes. |
|
Added fixes, @maxtruxa. |
|
Looking great. I don't see any problems with merging this. |
* Set promisify-any to use the declared Bluebird promise handler * Removed deprecated Promise.try and replaed with just using promisify * Changed getClient to always pass three parameters, with clientSecret being `null` when not needed * Simplified some of the promise chains for saveToken
6e91ad7 to
ade9b15
Compare
|
Thanks! |
The current library does not run well with node-style callback functions, which require promisification. Bluebird's native promisify will only promisify node-style callback functions, but will break existing promises.
.then.