-
Notifications
You must be signed in to change notification settings - Fork 25
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
feat: refactor core to use Promises instead of callbacks #55
Conversation
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 looks great!
But I am nervous about making such a large change this close to the major release.
I'd like to let @germanattanasio make the call on that.
@@ -48,11 +48,11 @@ export class BasicAuthenticator extends Authenticator implements AuthenticatorIn | |||
this.password = options.password; | |||
} | |||
|
|||
public authenticate(options: AuthenticateOptions, callback: AuthenticateCallback): void { | |||
public authenticate(options: AuthenticateOptions): Promise<void> { | |||
const authHeaderString = computeBasicAuthHeader(this.username, this.password); |
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.
I don't know about TypeScript but with JS, you need to always wrap the code within a promise in order to catch errors.
public authenticate(options: AuthenticateOptions): Promise<void> {
return new Promise((resolve, reject) => {
const authHeaderString = computeBasicAuthHeader(this.username, this.password);
const authHeader = { Authorization: authHeaderString }
options.headers = extend(true, {}, options.headers, authHeader);
resolve();
});
}
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.
Promises work the same in TS as they do JS. That is true, I just wasn't anticipating any errors here and wasn't handling them when I was using callbacks. But I am good with this approach here to be safe.
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.
I'm just trying to anticipate future changes to those methods that today don't return errors
*/ | ||
public getToken(cb: Function) { | ||
public getToken(): Promise<any> { | ||
if (!this.tokenInfo[this.tokenName] || this.isTokenExpired()) { |
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.
I think this should be wrap in a promise like my example above
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.
Since the requestToken
method also returns a Promise, I think it is cleaner to chain the Promises together than to create a new Promise altogether.
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.
What happens if this.tokenInfo
is undefined?
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.
It would throw an error that would not be rejected in the Promise, so the users rejection handling wouldn't catch it. Which would be bad. But we explicitly define the tokenInfo
object in the constructor: this.tokenInfo = {};
.
I understand what you're saying, I just don't know how much we want to account for a scenario like this that shouldn't ever happen. We were not accounting for any errors happening here before either. The behavior is staying the same. That said, if you think we need to be able to catch errors there, I will change the code
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.
I left some comments around wrapping the entire function as a promise rather than using Promise.resolve()
or Promise.reject()
In some scenarios I would think that is better but when returning a series of Promises in a row (like |
dc1d437
to
d1362d8
Compare
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.
The latest changes look good. Thanks!
d1362d8
to
d45348a
Compare
BREAKING CHANGE: None of the authenticators or request methods take callbacks as arguments anymore - they return Promises instead.
d45348a
to
bc6803e
Compare
BREAKING CHANGE: None of the authenticators or request methods take callbacks as arguments anymore - they return Promises instead.
BREAKING CHANGE: None of the authenticators or request methods take callbacks as arguments anymore - they return Promises instead.
# [1.0.0](v0.3.6...v1.0.0) (2019-10-03) ### Bug Fixes * Move check for serviceUrl to createRequest ([#47](#47)) ([6f04739](6f04739)) * parse result from response in token managers ([6bbe423](6bbe423)) * provide bundlers alternate file for browser support ([#58](#58)) ([88a9d16](88a9d16)) ### Build System * drop support for Node versions 6 and 8 ([#33](#33)) ([d47c737](d47c737)) ### Code Refactoring * look for credentials file in working dir before home dir ([#46](#46)) ([c5556de](c5556de)) * return detailed response as second callback argument ([#34](#34)) ([dc24154](dc24154)) ### Features * add `setServiceUrl` method as a setter for the `serviceUrl` property ([#41](#41)) ([cfb188f](cfb188f)) * add specific error handling for SSL errors with cloud private instances ([#54](#54)) ([056ec9a](056ec9a)) * export `UserOptions` interface from the BaseService ([#50](#50)) ([4f0075a](4f0075a)) * implement new authenticators to handle sdk authentication ([#37](#37)) ([f876b6d](f876b6d)) * refactor core to use Promises instead of callbacks ([#55](#55)) ([9ec8afd](9ec8afd)) ### BREAKING CHANGES * None of the authenticators or request methods take callbacks as arguments anymore - they return Promises instead. * Users that have credential files in both the working directory and the home directory will see a change in which one is used. * The internal property `url` no longer exists on the `baseOptions` object, it has been renamed to `serviceUrl` * The old style of passing credentials to the base service will no longer work. An Authenticator instance MUST be passed in to the base service constructor. * token managers no longer support user access tokens. use BearerTokenAuthenticator instead * The class names of the token managers have changed. * `Icp4dTokenManagerV1` renamed to `Cp4dTokenManager` * `IamTokenManagerV1` renamed to `IamTokenManager` * `JwtTokenManagerV1` renamed to `JwtTokenManager` * The public method `setAuthorizationInfo` is renamed to `setClientIdAndSecret` * The response body is no longer the 2nd callback argument, the detailed response is. The body is located under the `result` property. The `data` property is removed. * This SDK may no longer work with applications running on Node 6 or 8.
Refactors the entire library to use Promises instead of callbacks. This is a pretty big change but since the SDK is really the only "user", I don't think it will cause any problems.
The generated SDK code should be able to change slightly to achieve no difference in current behavior. The current plan is to start returning Promises first in the generated Watson SDK, with callbacks being an accommodation. We also want to start generating new services using only Promises. This PR enables that route, as it moves all callback handling out of the core and into the generated SDK.
If this is too big of a change to make too late in the game, that's fine, but this work is necessary to move towards a Promise-only approach and doing it this way gives us more flexibility in the generated SDKs to use either approach.
If this is agreeable, I will open a corresponding PR in the generator.
FYI: This PR makes heavy use of the fact that every
then
andcatch
block returns a Promise itself and that "returning" or "throwing" inside of these blocks, will resolve and reject in a later chained Promise, respectively. Where we were previously passing one callback around to multiple functions, we are now bubbling up results through chained Promises. Using the other method, we used to lose some error information that is now becoming visible. This required some small changes in the unit tests. On that point, I think the code is improved overall.