Promise chaining, use result of request for another one

I'm using ES6 within node.js. Long story short, I only now about callbacks and want to replace them with promises.

I made a test project to get an oauth2 token from an api/endpoint, refresh it and finally revoke it. The goal is, to give the response of the previous request to the next. My code looks like this:

const oauth2Adapter = require('./api/adapter/oauth2Adapter')

function test () {
oauth2Adapter.RequestNewAccessToken()
.then(function (response) {
  console.log(response)
  return oauth2Adapter.RefreshAccessToken(response.body)
})
.then(function (response) {
  return oauth2Adapter.RevokeAccessToken(response.body)
})
.then(console.log)
.catch(console.log)
}

test()

The first promise returns it's response. The next step is now to give it to the second promise as a parameter. But the second promise only receives an undefined object.

I'm a second year cs apprentice, any critic helps me and is appreciated.

Edit: adding the 'return' keyword didn't change the situation. The problem is that 'RefreshAccessToken' 'undefined' receives. Also I don't know if this helps, but here is the 'oauth2Adapter.js' code:

const Promise = require('promise')
const rp = require('request-promise')
const credentials = require('../../misc/credentials/Staging')

function RequestNewAccessToken () {
  try {
    const response = rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/token`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        username: credentials.username,
        password: credentials.password,
        grant_type: credentials.grantType
      },
      json: true
    })
    return Promise.resolve(response)
  } catch (error) {
    return Promise.reject(error)
  }
}

function RefreshAccessToken (token) {
  try {
    const response = rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/token`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        grant_type: 'refresh_token',
        refresh_token: token.refresh_token
      },
      json: true
    })
    return Promise.resolve(response)
  } catch (error) {
    return Promise.reject(error)
  }
}

function RevokeAccessToken (token) {
  try {
    const response = rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/revoke`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        token: token.access_token
      },
      json: true
    })
    return Promise.resolve(response)
  } catch (error) {
    return Promise.reject(error)
  }
}

module.exports = { RequestNewAccessToken, RefreshAccessToken, RevokeAccessToken }

If I execute the code, i get the following text by stdout:

Debugger attached.

    { access_token: '31744bf03a2fb92edb67fcbeead14f4ed8c540843c2439179a54b6439dc94c0e',
      token_type: 'Bearer',
      expires_in: 660,
      refresh_token: 'e53642c69bd0ad954d886dad7a437f88c8c269ecacf2cdcfebc8af1a2d0d9b1e',
      created_at: 1538471914 }
    TypeError: Cannot read property 'refresh_token' of undefined
        at Object.RefreshAccessToken (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/api/adapter/oauth2Adapter.js:28:28)
        at /Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/Main.js:7:28
        at tryCatcher (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/util.js:16:23)
        at Promise._settlePromiseFromHandler (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/promise.js:512:31)
        at Promise._settlePromise (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/promise.js:569:18)
        at Promise._settlePromise0 (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/promise.js:614:10)
        at Promise._settlePromises (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/promise.js:694:18)
        at _drainQueueStep (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/async.js:138:12)
        at _drainQueue (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/async.js:131:9)
        at Async._drainQueues (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/async.js:147:5)
        at Immediate.Async.drainQueues (/Users/quest1onmark/coding_stuff/nodejs/EdgeDeviceAdministration/node_modules/bluebird/js/release/async.js:17:14)
        at runCallback (timers.js:810:20)
        at tryOnImmediate (timers.js:768:5)
        at processImmediate [as _immediateCallback] (timers.js:745:5)
    Waiting for the debugger to disconnect...

    Process finished with exit code 0

Upvotes: 0

Views: 1528

Answers (3)

Jaromanda X
Jaromanda X

Reputation: 1

Your second code block is not using promises at all well

try the following instead

const Promise = require('promise')
const rp = require('request-promise')
const credentials = require('../../misc/credentials/Staging')

function RequestNewAccessToken () {
    return rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/token`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        username: credentials.username,
        password: credentials.password,
        grant_type: credentials.grantType
      },
      json: true
    });
}

function RefreshAccessToken (token) {
    return rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/token`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        grant_type: 'refresh_token',
        refresh_token: token.refresh_token
      },
      json: true
    });
}

function RevokeAccessToken (token) {
    return rp({
      method: 'POST',
      url: `${credentials.baseUrl}/oauth/revoke`,
      form: {
        client_id: credentials.apiKey,
        client_secret: credentials.apiSecret,
        token: token.access_token
      },
      json: true
    });
}

module.exports = { RequestNewAccessToken, RefreshAccessToken, RevokeAccessToken }

As for your code that USES this - you console.log(response) which has the required format, but then you oauth2Adapter.RefreshAccessToken(response.body) ... response has no body!

So, simply do:

const oauth2Adapter = require('./api/adapter/oauth2Adapter')
function test () {
    return oauth2Adapter.RequestNewAccessToken()
    .then(response => oauth2Adapter.RefreshAccessToken(response))
    .then(response => oauth2Adapter.RevokeAccessToken(response))
    .then(console.log)
    .catch(console.log)
}
test()

but, since you pass response straight to the next function without any processing, you can also do

const oauth2Adapter = require('./api/adapter/oauth2Adapter')
function test () {
    return oauth2Adapter.RequestNewAccessToken()
    .then(oauth2Adapter.RefreshAccessToken)
    .then(oauth2Adapter.RevokeAccessToken)
    .then(console.log)
    .catch(console.log)
}
test()

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222369

Promises should be properly chained. This means that then and catch callbacks should return a promise to chain, in case there's one.

Also, response parameter is parsed response body when json: true is used. If a server responds with token object, then it should be passed as an argument to the function that expects it:

...
.then(function (response) {
  console.log(response)
  return oauth2Adapter.RefreshAccessToken(response)
})
...

Upvotes: 0

shinglesmingles
shinglesmingles

Reputation: 540

Promises are chained by returning another Promise at the end of the then block. It looks like you didn't call return properly in the first then block. You should correct that as follows:

oauth2Adapter.RequestNewAccessToken()
.then(function (requestReponse) {
  console.log(response)
  return oauth2Adapter.RefreshAccessToken()
})
.then(function (refreshResponse) {
  return oauth2Adapter.RevokeAccessToken(JSON.parse(refreshResponse.body))
})

As a sidenote, I like to name my callback args differently with each Promise return, which will help to keep things clean!

Upvotes: 1

Related Questions