Repository: auth0/node-auth0
Pull request #150 (2016-12-15 01:22:11)

Added support for Resource Servers CRUD endpoints
PR for #124 


Patch:
diff --git a/src/management/ResourceServersManager.js b/src/management/ResourceServersManager.js
new file mode 100644
index 000000000..46eaa16bb
--- /dev/null
+++ b/src/management/ResourceServersManager.js
@@ -0,0 +1,167 @@
+var RestClient = require('rest-facade').Client;
+var ArgumentError = require('../exceptions').ArgumentError;
+var utils = require('../utils');
+
+/**
+ * @class ResourceServersManager
+ * Auth0 Resource Servers Manager.
+ *
+ * {@link https://auth0.com/docs/api/management/v2#!/Resource_Servers Resource Servers} represents
+ * your APIs.
+ * You can learn more about this in the
+ * {@link https://auth0.com/docs/api-auth API Authorization} section of the
+ * documentation.
+ * @constructor
+ * @memberOf module:management
+ *
+ * @param {Object} options            The client options.
+ * @param {String} options.baseUrl    The URL of the API.
+ * @param {Object} [options.headers]  Headers to be included in all requests.
+ */
+
+var ResourceServersManager = function (options) {
+  if (options === null || typeof options !== 'object') {
+    throw new ArgumentError('Must provide resource server options');
+  }
+
+  if (options.baseUrl === null || options.baseUrl === undefined) {
+    throw new ArgumentError('Must provide a base URL for the API');
+  }
+
+  if ('string' !== typeof options.baseUrl || options.baseUrl.length === 0) {
+    throw new ArgumentError('The provided base URL is invalid');
+  }
+
+  /**
+   * Options object for the Rest Client instance.
+   *
+   * @type {Object}
+   */
+  var apiOptions = {
+    headers: options.headers,
+    query: { repeatParams: false }
+  };
+
+  /**
+   * Provides an abstraction layer for consuming the
+   * {@link https://auth0.com/docs/api/v2#!/ResourceServers Auth0 Resource Servers endpoint}.
+   *
+   * @type {external:RestClient}
+   */
+  this.resource = new RestClient(options.baseUrl + '/resource-servers/:id', apiOptions);
+};
+
+/**
+ * Create an API (Resource Server).
+ *
+ * @method    create
+ * @memberOf  module:management.ResourceServersManager.prototype
+ *
+ * @example
+ * management.resourceServers.create(data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Resource Server created.
+ * });
+ *
+ * @param   {Object}    data     Resource Server data object.
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ResourceServersManager, 'create', 'resource.create');
+
+/**
+ * Get all resource servers.
+ *
+ * @method    getAll
+ * @memberOf  module:management.ResourceServersManager.prototype
+ *
+ * @example
+ * management.resourceServers.getAll(function (err, resourceServers) {
+ *   console.log(resourceServers.length);
+ * });
+ *
+ * @param   {Function}  [cb]    Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ResourceServersManager, 'getAll', 'resource.getAll');
+
+
+/**
+ * Get a Resource Server.
+ *
+ * @method    get
+ * @memberOf  module:management.ResourceServersManager.prototype
+ *
+ * @example
+ * management.resourceServers.get({ id: RESOURCE_SERVER_ID }, function (err, resourceServer) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(resourceServer);
+ * });
+ *
+ * @param   {Object}    params            Resource Server parameters.
+ * @param   {String}    params.id         Resource Server ID.
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ResourceServersManager, 'get', 'resource.get');
+
+/**
+ * Update an existing resource server.
+ *
+ * @method    update
+ * @memberOf  module:management.ResourceServersManager.prototype
+ *
+ * @example
+ * var data = { name: 'newResourceServerName' };
+ * var params = { id: RESOURCE_SERVER_ID };
+ *
+ * management.resourceServers.update(params, data, function (err, resourceServer) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(resourceServer.name);  // 'newResourceServernName'
+ * });
+ *
+ * @param   {Object}    params            Resource Server parameters.
+ * @param   {String}    params.id         Resource Server ID.
+ * @param   {Object}    data              Updated Resource Server data.
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ResourceServersManager, 'update', 'resource.patch');
+
+/**
+ * Delete an existing Resource Server.
+ *
+ * @method    delete
+ * @memberOf  module:management.ResourceServersManager.prototype
+ *
+ * @example
+ * management.resourceServers.delete({ id: RESOURCE_SERVER_ID }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Resource Server deleted.
+ * });
+ *
+ * @param   {Object}    params            Resource Server parameters.
+ * @param   {String}    params.id         Resource Server ID.
+ * @param   {Function}  [cb]              Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ResourceServersManager, 'delete', 'resource.delete');
+
+module.exports = ResourceServersManager;
\ No newline at end of file
diff --git a/src/management/index.js b/src/management/index.js
index 9cc6b6f10..2721bc02f 100644
--- a/src/management/index.js
+++ b/src/management/index.js
@@ -21,6 +21,7 @@ var TenantManager = require('./TenantManager');
 var JobsManager = require('./JobsManager');
 var TicketsManager = require('./TicketsManager');
 var LogsManager = require('./LogsManager');
+var ResourceServersManager = require('./ResourceServersManager');
 
 var BASE_URL_FORMAT = 'https://%s/api/v2';
 
@@ -177,6 +178,15 @@ var ManagementClient = function (options) {
    * @type {LogsManager}
    */
   this.logs = new LogsManager(managerOptions);
+
+  /**
+   * Simple abstraction for performing CRUD operations on the
+   * resource servers endpoint.
+   *
+   * @type {ResourceServersManager}
+   */
+  this.resourceServers = new ResourceServersManager(managerOptions);
+
 };
 
 
@@ -1426,4 +1436,119 @@ utils.wrapPropertyMethod(ManagementClient, 'getLog', 'logs.get');
 utils.wrapPropertyMethod(ManagementClient, 'getLogs', 'logs.getAll');
 
 
+/**
+ * Create a new resource server.
+ *
+ * @method    createResourceServer
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.createResourceServer(data, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Resource Server created.
+ * });
+ *
+ * @param   {Object}    data     Resource Server data object.
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'createResourceServer', 'resourceServers.create');
+
+/**
+ * Get all resource servers.
+ *
+ * @method    getResourceServers
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.getResourceServers(function (err, resourceServers) {
+ *   console.log(resourceServers.length);
+ * });
+ *
+ * @param   {Object}    data     Connection data object.
+ * @param   {Function}  [cb]     Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'getResourceServers', 'resourceServers.getAll');
+
+
+/**
+ * Get a Resource Server.
+ *
+ * @method    getResourceServer
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.getResourceServer({ id: RESOURCE_SERVER_ID }, function (err, resourceServer) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(resourceServer);
+ * });
+ *
+ * @param   {Object}    params          Resource Server parameters.
+ * @param   {String}    params.id       Resource Server ID.
+ * @param   {Function}  [cb]            Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'getResourceServer', 'resourceServers.get');
+
+
+/**
+ * Delete an existing resource server.
+ *
+ * @method    deleteResourceServer
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * management.deleteResourceServer({ id: RESOURCE_SERVER_ID }, function (err) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   // Resource Server deleted.
+ * });
+ *
+ * @param   {Object}    params          Resource Server parameters.
+ * @param   {String}    params.id       Resource Server ID.
+ * @param   {Function}  [cb]            Callback function.
+ *
+ * @return  {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'deleteResourceServer', 'resourceServers.delete');
+
+
+/**
+ * Update an existing resource server.
+ *
+ * @method    updateResourceServer
+ * @memberOf  module:management.ManagementClient.prototype
+ *
+ * @example
+ * var data = { name: 'newResourceServerName' };
+ * var params = { id: RESOURCE_SERVER_ID };
+ *
+ * management.updateResourceServer(params, data, function (err, resourceServer) {
+ *   if (err) {
+ *     // Handle error.
+ *   }
+ *
+ *   console.log(resourceServer.name);  // 'newResourceServerName'
+ * });
+ *
+ * @param   {Object}    params          Resource Server parameters.
+ * @param   {String}    params.id       Resource Server ID.
+ * @param   {Object}    data            Updated Resource Server data.
+ * @param   {Function}  [cb]            Callback function.
+ *
+ * @return    {Promise|undefined}
+ */
+utils.wrapPropertyMethod(ManagementClient, 'updateResourceServer', 'resourceServers.update');
 module.exports = ManagementClient;


Test patch:
diff --git a/test/management/resource-servers.tests.js b/test/management/resource-servers.tests.js
new file mode 100644
index 000000000..c0e56a8e3
--- /dev/null
+++ b/test/management/resource-servers.tests.js
@@ -0,0 +1,566 @@
+var expect = require('chai').expect;
+var nock = require('nock');
+var Promise = require('bluebird');
+
+var SRC_DIR = '../../src';
+var API_URL = 'https://tenant.auth0.com';
+
+var ResourceServersManager = require(SRC_DIR + '/management/ResourceServersManager');
+var ArgumentError = require(SRC_DIR + '/exceptions').ArgumentError;
+
+describe('ResourceServersManager', function () {
+
+  before(function () {
+    this.token = 'TOKEN';
+    this.resourceServers = new ResourceServersManager({
+      headers: {
+        authorization: 'Bearer ' + this.token
+      },
+      baseUrl: API_URL
+    });
+  });
+
+  afterEach(function () {
+    nock.cleanAll();
+  });
+
+  describe('instance', function () {
+    var methods = ['get', 'create', 'update', 'delete'];
+
+    methods.forEach(function (method) {
+      it('should have a ' + method + ' method', function () {
+        expect(this.resourceServers[method])
+          .to.exist
+          .to.be.an.instanceOf(Function);
+      })
+    });
+  });
+
+  describe('#constructor', function () {
+    it('should error when no options are provided', function () {
+      expect(ResourceServersManager)
+        .to.throw(ArgumentError, 'Must provide resource server options');
+    });
+
+
+    it('should throw an error when no base URL is provided', function () {
+      var resourceServerManager = ResourceServersManager.bind(null, {});
+
+      expect(resourceServerManager)
+        .to.throw(ArgumentError, 'Must provide a base URL for the API');
+    });
+
+
+    it('should throw an error when the base URL is invalid', function () {
+      var resourceServerManager = ResourceServersManager.bind(null, { baseUrl: '' });
+
+      expect(resourceServerManager)
+        .to.throw(ArgumentError, 'The provided base URL is invalid');
+    });
+  });
+
+  describe('#getAll', function () {
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .get('/resource-servers')
+        .reply(200);
+    })
+
+
+    it('should accept a callback', function (done) {
+      this
+        .resourceServers
+        .getAll(function () {
+        done();
+      });
+    });
+
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .resourceServers
+        .getAll()
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/resource-servers')
+        .reply(500);
+
+      this
+        .resourceServers
+        .getAll()
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+
+    it('should pass the body of the response to the "then" handler', function (done) {
+      nock.cleanAll();
+
+      var data = [{ test: true }];
+      var request = nock(API_URL)
+        .get('/resource-servers')
+        .reply(200, data);
+
+      this
+        .resourceServers
+        .getAll()
+        .then(function (resourceServers) {
+          expect(resourceServers)
+            .to.be.an.instanceOf(Array);
+
+          expect(resourceServers.length)
+            .to.equal(data.length);
+
+          expect(resourceServers[0].test)
+            .to.equal(data[0].test);
+
+          done();
+        });
+    });
+
+
+    it('should perform a GET request to /api/v2/resource-servers', function (done) {
+      var request = this.request;
+
+      this
+        .resourceServers
+        .getAll()
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the Authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/resource-servers')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .resourceServers
+        .getAll()
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+          done();
+        });
+    });
+  });
+
+
+  describe('#get', function () {
+    var params = { id: 5 };
+    var data = {
+      id: params.id,
+      name: 'Test Resource Server'
+    };
+
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .get('/resource-servers/' + data.id)
+        .reply(200);
+    })
+
+
+    it('should accept a callback', function (done) {
+      this
+        .resourceServers
+        .get(params, function () {
+          done();
+        });
+    });
+
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .resourceServers
+        .get(params)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/resource-servers/' + params.id)
+        .reply(500);
+
+      this
+        .resourceServers
+        .get()
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+
+    it('should pass the body of the response to the "then" handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/resource-servers/' + params.id)
+        .reply(200, data);
+
+      this
+        .resourceServers
+        .get(params)
+        .then(function (connection) {
+          expect(connection.id)
+            .to.equal(data.id);
+
+          done();
+        });
+    });
+
+
+    it('should perform a GET request to /api/v2/resource-servers/:id', function (done) {
+      var request = this.request;
+
+      this
+        .resourceServers
+        .get(params)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the Authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .get('/resource-servers')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .resourceServers
+        .get()
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+  });
+
+
+  describe('#create', function () {
+    var data = {
+      name: 'Acme Backend API',
+      options: {}
+    };
+
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .post('/resource-servers')
+        .reply(200, data);
+    })
+
+
+    it('should accept a callback', function (done) {
+      this
+        .resourceServers
+        .create(data, function () {
+          done();
+        });
+    });
+
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .resourceServers
+        .create(data)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/resource-servers')
+        .reply(500);
+
+      this
+        .resourceServers
+        .create(data)
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+
+    it('should perform a POST request to /api/v2/resource-servers', function (done) {
+      var request = this.request;
+
+      this
+        .resourceServers
+        .create(data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should pass the data in the body of the request', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/resource-servers', data)
+        .reply(200);
+
+      this
+        .resourceServers
+        .create(data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the Authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .post('/resource-servers')
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .resourceServers
+        .create(data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+
+
+  describe('#update', function () {
+    var params = { id: 5 };
+    var data = {
+      id: 5,
+      name: 'Acme Backend API',
+      options: {}
+    };
+
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .patch('/resource-servers/' + data.id)
+        .reply(200, data);
+    })
+
+
+    it('should accept a callback', function (done) {
+      this
+        .resourceServers
+        .update(params, data, function () {
+          done();
+        });
+    });
+
+
+    it('should return a promise if no callback is given', function (done) {
+      this
+        .resourceServers
+        .update(params, data)
+        .then(done.bind(null, null))
+        .catch(done.bind(null, null));
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/resource-servers/' + data.id)
+        .reply(500);
+
+      this
+        .resourceServers
+        .update(params, data)
+        .catch(function (err) {
+          expect(err)
+            .to.exist
+            .to.be.an.instanceOf(Error);
+
+          done();
+        });
+    });
+
+
+    it('should perform a PATCH request to /api/v2/resource-servers/:id', function (done) {
+      var request = this.request;
+
+      this
+        .resourceServers
+        .update(params, data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should pass the data in the body of the request', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/resource-servers/' + data.id, data)
+        .reply(200);
+
+      this
+        .resourceServers
+        .update(params, data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the Authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .patch('/resource-servers/' + data.id)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .resourceServers
+        .update(params, data)
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+
+  describe('#delete', function () {
+    var id = 5;
+
+    beforeEach(function () {
+      this.request = nock(API_URL)
+        .delete('/resource-servers/' + id)
+        .reply(200);
+    });
+
+
+    it('should accept a callback', function (done) {
+      this
+        .resourceServers
+        .delete({ id: id }, done.bind(null, null));
+    });
+
+
+    it('should return a promise when no callback is given', function (done) {
+      this
+        .resourceServers
+        .delete({ id: id })
+        .then(done.bind(null, null));
+    });
+
+
+    it('should perform a DELETE request to /resource-servers/' + id, function (done) {
+      var request = this.request;
+
+      this
+        .resourceServers
+        .delete({ id: id })
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+
+
+    it('should pass any errors to the promise catch handler', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/resource-servers/' + id)
+        .reply(500);
+
+      this
+        .resourceServers
+        .delete({ id: id })
+        .catch(function (err) {
+          expect(err)
+            .to.exist;
+
+          done();
+        });
+    });
+
+
+    it('should include the token in the Authorization header', function (done) {
+      nock.cleanAll();
+
+      var request = nock(API_URL)
+        .delete('/resource-servers/' + id)
+        .matchHeader('Authorization', 'Bearer ' + this.token)
+        .reply(200)
+
+      this
+        .resourceServers
+        .delete({ id: id })
+        .then(function () {
+          expect(request.isDone())
+            .to.be.true;
+
+          done();
+        });
+    });
+  });
+
+});
\ No newline at end of file