Skip to content
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

Promise API and consistent callback function signature #261

Merged
merged 14 commits into from Aug 2, 2016
Merged

Promise API and consistent callback function signature #261

merged 14 commits into from Aug 2, 2016

Conversation

adamreisnz
Copy link
Contributor

@adamreisnz adamreisnz commented Jul 26, 2016

This PR addresses the following issues:

Notable changes:

  • Extracted some logic into helpers
  • Using a getEmptyRequest helper to avoid code duplication
  • emtpyRequest now accepts an object with data to extend the empty request with, this will allow simpler syntax for initializing requests.
  • Callback function now receives two parameters as per Node conventions (error, response)
  • If no callback provided, the method will return a promise instead.
  • Implemented promise API when not passing a callback function
  • Using native Promise by default if present, but allow users to override this with any other implementation by setting Sendgrid.Promise to any value, e.g. Sendgrid.Promise = require('bluebird')

Example usage:

let sendgrid = require('sendgrid');
sendgrid.SendGrid.Promise = require('bluebird');

let sg = sendgrid.SendGrid(process.env.SENDGRID_API_KEY);
let request = sg.emptyRequest({
  method: 'POST',
  path: '/v3/mail/send',
  body: mail.toJSON()
});

//Send request (returns promise)
sg.API(request)
  .then(response => ...)
  .catch(error => ...);

//Send request (using callback)
sg.API(request, (error, response) => {
  if (error) {
    //boo
  }
  //response always populated, even with error
});

@thinkingserious thinkingserious added type: community enhancement feature request not on Twilio's roadmap status: cla signed labels Jul 26, 2016
@adamreisnz
Copy link
Contributor Author

@thinkingserious can you check why the build is failing? I haven't made any API changes in this PR yet, so everything should still be working, yet all the tests seem to fail on an incorrect status code.

@thinkingserious
Copy link
Contributor

Ah, since you are not part of the SendGrid repo, Travis is not loading the MOCK_HOST variable. I'll send instructions on how to create the test environment locally.

@adamreisnz
Copy link
Contributor Author

Yes I figured that's why the tests would be failing locally, but on Travis it should still work, no?

@thinkingserious
Copy link
Contributor

To test locally:

  1. Install Prism: https://stoplight.io/prism
  2. Run ./prism run --mock --list --spec https://raw.githubusercontent.com/sendgrid/sendgrid-oai/master/oai_stoplight.json

This will set up a mock local SendGrid server. When you run your tests locally they should pass.

For Node.js, we have have not automated this yet on Travis (it's coming), so it relies on their hosted server, whose unique URL is hidden behind the MOCK_HOST variable. Travis will only load that variable for those in the sengrid repo.

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Jul 27, 2016

Gotcha. I have added the changes to the API here. I might actually have to update the tests, as the callback now receives parameters in different order as per Node conventions.

Notable changes:

  • Extracted some logic into helpers
  • Use getEmptyRequest helper to avoid duplication
  • Use native Promise by default if present, but allow users to override this with any other implementation
  • Callback now receives two parameters as per Node conventions (error, response)
  • If no callback provided, the method will return a promise instead.
  • Removed unused ESLint plugins from package.json
  • emtpyRequest now accepts an object with data to extend the empty request with, this will allow simpler syntax for initializing requests.

Example usage:

//Build request
let request = sg.emptyRequest({
  method: 'POST',
  path: '/v3/mail/send',
  body: mail.toJSON()
});

//Send request (returns promise)
sg.API(request)
  .then(response => ...)
  .catch(error => ...);

//Send request (using callback)
sg.API(request, (error, response) => {
  if (error) {
    //boo
  }
  //response always populated, even with error
});

@thinkingserious
Copy link
Contributor

This is awesome!

Can you please allow us to send you some swag? Just email dx@sendgrid.com with a mailing address and T-shirt size.

@adamreisnz
Copy link
Contributor Author

Sure will do, thanks :)

I've just pushed another commit which updates the tests and examples to use the new function signature. As this technically is a breaking change from the current version, you might want to release this under a new major version.

However, as it could also be considered a "fix" to adhere to Node standards, maybe you can get away with a minor release as well. But I'll leave that up to you :)

Let me know if there's anything else.

@adamreisnz
Copy link
Contributor Author

Have run the tests locally with Prism and all pass 👍

@thinkingserious
Copy link
Contributor

Awesome, love it!

I've gotten this into our backlog for review and merge.

Unfortunately, we have quite a few tickets in front of it, but this issue can move up our queue if others +1 or add comments.

@adamreisnz adamreisnz changed the title Add ESLint configuration and fix issues Promise API and consistent callback function signature Jul 27, 2016
@adamreisnz
Copy link
Contributor Author

adamreisnz commented Jul 27, 2016

@thinkingserious I've updated the PR title and description to reflect what has changed. I think I might also remove the redundant sendgrid.SendGrid API, as it doesn't seem to add much value. The empty request that also gets exposed in the main sendgrid export is also accessible via the sendgrid.SendGrid function, so it seems a bit redundant.

Mind if we just export the main SendGrid function so one can do:

let sendgrid = require('sendgrid');
let sg = sendgrid(process.env.SENDGRID_API_KEY);

Instead of the more verbose:

let sendgrid = require('sendgrid');
let sg = sendgrid.SendGrid(process.env.SENDGRID_API_KEY);

@thinkingserious
Copy link
Contributor

Beautiful and thanks again!

@adamreisnz
Copy link
Contributor Author

adamreisnz commented Jul 27, 2016

Ok, done. I've also updated the README.md to reflect the new API.

The emptyRequest method's name with it's new API is a bit misleading. Perhaps we should rename it to something like makeRequest.

@jamesdixon
Copy link

+1 LGTM

@thinkingserious
Copy link
Contributor

@jamesdixon thanks for the vote, I've added your vote to help move this up the queue.

@liatreis
Copy link

+1

@thinkingserious
Copy link
Contributor

@adambuczynski,

I'm now reviewing this pull request :)

So far, I've just tried to run the tests (mocha) and get the following error:

/Users/thinkingserious/Workspace/sendgrid/sendgrid-nodejs/lib/sendgrid.js:78
  this.API = function(request, callback) {
           ^

TypeError: Cannot set property 'API' of undefined
    at SendGrid (/Users/thinkingserious/Workspace/sendgrid/sendgrid-nodejs/lib/sendgrid.js:78:12)
    at Suite.<anonymous> (/Users/thinkingserious/Workspace/sendgrid/sendgrid-nodejs/test/test.js:13:12)
    at context.describe.context.context (/usr/local/lib/node_modules/mocha/lib/interfaces/bdd.js:47:10)
    at Object.<anonymous> (/Users/thinkingserious/Workspace/sendgrid/sendgrid-nodejs/test/test.js:4:1)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at /usr/local/lib/node_modules/mocha/lib/mocha.js:219:27
    at Array.forEach (native)
    at Mocha.loadFiles (/usr/local/lib/node_modules/mocha/lib/mocha.js:216:14)
    at Mocha.run (/usr/local/lib/node_modules/mocha/lib/mocha.js:468:10)
    at Object.<anonymous> (/usr/local/lib/node_modules/mocha/bin/_mocha:403:18)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:142:18)
    at node.js:939:3

@adamreisnz
Copy link
Contributor Author

@thinkingserious interesting, I didn't make any changes to the architectural style of that core function, the this reference was always there:

https://github.com/sendgrid/sendgrid-nodejs/pull/261/files#diff-821a7fec86de51dd671e7622dc4cd6d9R78

Also, I didn't run into this error running the tests.

But I can refactor it to hide the API helper function altogether as a "private" method. Would you prefer that, or do you want to analyze the issue a bit further?

@thinkingserious
Copy link
Contributor

@adambuczynski,

How did you run the tests?

@adamreisnz
Copy link
Contributor Author

Via the way you suggested above. However, I tried again and have been able to reproduce it now as well. I think it's related to the way the Sendgrid function is exported now.

I have addressed this by referencing the Sendgrid function directly rather than using this, since the function is not meant to be called as a constructor with new anyway.

Tests are working and passing now.

@thinkingserious
Copy link
Contributor

That did the trick :)

@adamreisnz
Copy link
Contributor Author

Excellent, let me know if anything else comes up.

@thinkingserious thinkingserious merged commit 93763a7 into sendgrid:master Aug 2, 2016
@adamreisnz
Copy link
Contributor Author

Great, thanks for merging. How are you going to version these changes?

@thinkingserious
Copy link
Contributor

I'm working on that right now. This will be a major version bump to 4.0. Should be done in about ~10 min.

@adamreisnz
Copy link
Contributor Author

Ok sounds sensible.

Would you like to release it as a RC first and see if we can make other improvements that might be API breaking? That way we could include them without having to do another major release in the future.

@thinkingserious
Copy link
Contributor

https://github.com/sendgrid/sendgrid-nodejs/releases/tag/v4.0.0

@thinkingserious
Copy link
Contributor

We don't currently have a RC workflow, but that sounds interesting.

For now, we just make major version bumps when something breaks. We follow the semver.org convention.

@thinkingserious
Copy link
Contributor

@adambuczynski oops, looks like we forget to remove the let's for var's. We have some breakage on the older node versions: https://travis-ci.org/sendgrid/sendgrid-nodejs/builds/149293172

@thinkingserious
Copy link
Contributor

#264

@thinkingserious
Copy link
Contributor

For Node v.10 looks like I need to catch this error: https://travis-ci.org/sendgrid/sendgrid-nodejs/jobs/149295924#L228

@adamreisnz
Copy link
Contributor Author

Ok I'll have a look into these issues tomorrow. I am so used to using let that it's become a habit, and I never use var anymore, so they might have snuck in by accident ;)

@thinkingserious
Copy link
Contributor

thinkingserious commented Aug 2, 2016

No worries, just about done fixing the issues :)

This will be a 4.0.1 fix.

@adamreisnz
Copy link
Contributor Author

Cool, as for the Promise error you can probably wrap that in an if statement to see if Promise is defined.

@thinkingserious
Copy link
Contributor

Yes, the build is passing now :)

https://travis-ci.org/sendgrid/sendgrid-nodejs/builds/149298361

@thinkingserious
Copy link
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: community enhancement feature request not on Twilio's roadmap
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants