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

Added the ability to use the library with Promise or Async/Await syntax. #31

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
language: node_js
node_js:
- "6"
- "7"
- "8"
- "9"
- "10"
- "12"
- "14"
- "node"
before_install:
- npm install
Expand Down
35 changes: 35 additions & 0 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,41 @@ Client.prototype.jsonApiCall = function (method, path, params, callback) {
})
}

/**
* Works just like the jsonApiCall function, but instead returns a Promise
* that will throw when the "stat" field does not equal "OK"
* @param {"GET"|"PUT"|"POST"|"DELETE"} method The HTTP method to use for the request
* @param {string} path The url path for the request
* @param {Object} params JSON object that contains the key/values for POST/PUT requests or queryparams for GET requests
* @returns {Object} A JSON object representing the response (JSON.parse called on the returned string)
*/
Client.prototype.jsonApiCallAsync = function (method, path, params) {
return new Promise((resolve, reject) => {
this.jsonApiCall(method, path, params, (data) => {
if (data.stat === 'OK') return resolve(data)
else return reject(new Error(data.message))
})
})
}

/**
* Works just like the jsonApiCall function, but instead returns a Promise
* that will throw when the "stat" field does not equal "OK"
* @param {"GET"|"PUT"|"POST"|"DELETE"} method The HTTP method to use for the request
* @param {string} path The url path for the request
* @param {Object} params JSON object that contains the key/values for POST/PUT requests or queryparams for GET requests
* @returns {string} The raw string response from the API
*/
Client.prototype.apiCallAsync = function (method, path, params) {
return new Promise((resolve, reject) => {
this.apiCall(method, path, params, (dataString) => {
let temp = JSON.parse(dataString)
if (temp.stat === 'OK') return resolve(dataString)
else return reject(new Error(temp.message))
})
})
}

module.exports = {
'Client': Client
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@duosecurity/duo_api",
"version": "1.2.1",
"version": "1.3.0",
"license": "BSD-3-Clause",
"description": "Duo API SDK for Node.js applications",
"homepage": "https://www.duosecurity.com/api",
Expand Down
46 changes: 46 additions & 0 deletions tests/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,50 @@ describe('Verifying rate limited request retries', function () {
currentWaitSecs = currentWaitSecs * BACKOFF_FACTOR
})
})

describe('Testing async calls', function () {
it('Should properly parse and return json data', function (done) {
let currentWaitSecs = 1000
let rateLimitedScope = addRequests(RATE_LIMITED_RESP_CODE)
addRequests(OK_RESP_CODE)
client
.jsonApiCallAsync('GET', '/foo/bar', {})
.then((res) => {
assert.strictEqual(res.stat, 'OK')
})
.catch((err) => {
assert.fail(err.message)
})
.finally(() => done())

// Don't tick the clock until after the request has been replied to,
// otherwise we'll move the clock forward before adding the retry attempt
// via setTimeout.
rateLimitedScope.on('replied', function (req, interceptor) {
clock.tick(currentWaitSecs + MAX_RANDOM_OFFSET)
})
})

it('Should throw an error when the async function detects a problem', function (done) {
let currentWaitSecs = 1000
let scope = addRequests(RATE_LIMITED_RESP_CODE, 7)

client.jsonApiCallAsync('GET', '/foo/bar/does/not/exist', {})
.then((res) => {
assert.fail('Should not get a response')
})
.catch((err) => {
assert.ok(err.message, 'Did not receive an error message')
})
.finally(() => done())

// Don't tick the clock until after the request has been replied to,
// otherwise we'll move the clock forward before adding the retry attempt
// via setTimeout.
scope.on('replied', function (req, interceptor) {
clock.tick(currentWaitSecs + MAX_RANDOM_OFFSET)
currentWaitSecs = currentWaitSecs * BACKOFF_FACTOR
})
})
})
})