From 3bce48742175dee24701ea32d863f9cebc8c6df8 Mon Sep 17 00:00:00 2001 From: Michael Krotscheck Date: Fri, 26 Aug 2016 12:14:35 -0700 Subject: [PATCH] Passed tokens may now be promises. Tokens passed to token-requiring API methods may now also be promises, permitting promise-based request chaining across API's. For example: keystone .issueToken() .then((token) => glance.imageList(token)); ...or: const tokenPromise = keystone.issueToken(); Promise.all([ glance.imageList(tokenPromise), neutron.networkList(tokenPromise), nova.flavorList(tokenPromise) ]).then(([images, networks, flavors]) => { return nova.instanceCreate( ... ); }); These updates have been wrapped into a private method, which can be used for other API's as well. revokeToken is the noted exception, as it may have to resolve TWO tokens (auth and subject). Change-Id: I24e0a1e979d2aaedc6a25e378bd9d99f51ece595 --- src/keystone.js | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/src/keystone.js b/src/keystone.js index a16c74f..f5ec530 100644 --- a/src/keystone.js +++ b/src/keystone.js @@ -56,6 +56,30 @@ export default class Keystone { return pointer; } + /** + * This method builds common components of a keystone request. It converts any passed token + * into a promise, resolves the base URL, and then passes the results as an .all() promise, + * which may be destructured in a followup request. + * + * @param {Promise|String} token A promise, or string, representing a token. + * @returns {Promise} A promise which resolves with [url, token]. + * @private + */ + _requestComponents (token = null) { + // Make sure the token is a promise. + let headerPromise = Promise + .resolve(token) + .then((token) => { + if (token) { + return { + 'X-Auth-Token': token + }; + } + return {}; + }); + return Promise.all([this.serviceEndpoint(), headerPromise]); + } + /** * Retrieve all the API versions available. * @@ -186,13 +210,15 @@ export default class Keystone { * @returns {Promise.} A promise which will resolve if the token has been successfully revoked. */ tokenRevoke (token, adminToken = null) { - let headers = { - 'X-Subject-Token': token, - 'X-Auth-Token': adminToken || token - }; - - return this.serviceEndpoint() - .then((url) => this.http.httpRequest('DELETE', `${url}auth/tokens`, headers)); + return Promise + .all([this.serviceEndpoint(), token, adminToken]) + .then(([url, token, adminToken]) => { + return [url, { + 'X-Subject-Token': token, + 'X-Auth-Token': adminToken || token + }]; + }) + .then(([url, headers]) => this.http.httpRequest('DELETE', `${url}auth/tokens`, headers)); } /** @@ -202,14 +228,9 @@ export default class Keystone { * @returns {Promise.} A promise which will resolve with the service catalog. */ catalogList (token = null) { - const headers = {}; - if (token) { - headers['X-Auth-Token'] = token; - } - return this - .serviceEndpoint() - .then((url) => this.http.httpRequest('GET', `${url}auth/catalog`, headers)) + ._requestComponents(token) + .then(([url, headers]) => this.http.httpRequest('GET', `${url}auth/catalog`, headers)) .then((response) => response.json()) .then((body) => body.catalog); }