Skip to content

Commit

Permalink
Move all API resources to under a single 'api' topic (#19)
Browse files Browse the repository at this point in the history
* Truncate 'api:v2010:accounts' down to just 'api'

* Move all advanced API topics to under 'api' and 'api:core'
  • Loading branch information
childish-sambino authored May 14, 2019
1 parent d02a3ac commit c1f87c3
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 27 deletions.
4 changes: 2 additions & 2 deletions docs/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ At this stage in the `twilio-cli`, we have exposed commands that mirror the Twil

## Recipe 1: Purchase a phone number

```twilio api:v2010:accounts:available-phone-numbers:local:list --area-code="209" --country-code US -o json```
```twilio api:core:available-phone-numbers:local:list --area-code="209" --country-code US -o json```

(This command currently throws an error claiming a missing sid)

Then, once you find the desired number, execute:
```twilio api:v2010:accounts:incoming-phone-numbers:create --phone-number="+12095551212"```
```twilio api:core:incoming-phone-numbers:create --phone-number="+12095551212"```
5 changes: 2 additions & 3 deletions src/base-commands/twilio-api-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { doesObjectHaveProperty } = require('@twilio/cli-core').services.JSUtils;
const { validateSchema } = require('../services/api-schema/schema-validator');
const { kebabCase, camelCase } = require('../services/naming-conventions');
const ResourcePathParser = require('../services/resource-path-parser');
const { getActionDescription } = require('../services/twilio-api');
const { getActionDescription, isApi2010 } = require('../services/twilio-api');

// Open API type to oclif flag type mapping. For numerical types, we'll do validation elsewhere.
const typeMap = {
Expand Down Expand Up @@ -152,13 +152,12 @@ TwilioApiCommand.setUpNewCommandClass = NewCommandClass => {

// Parameters
const cmdFlags = {};
const isApi2010 = domainName === 'api' && versionName === 'v2010';
action.parameters.forEach(param => {
const flagName = kebabCase(param.name);
const flagConfig = {
description: sanitizeDescription(param.description),
// AccountSid on api.v2010 not required, we can get from the current project
required: flagName === ACCOUNT_SID_FLAG && isApi2010 ? false : param.required,
required: flagName === ACCOUNT_SID_FLAG && isApi2010(domainName, versionName) ? false : param.required,
multiple: param.schema.type === 'array',
apiDetails: {
parameter: param,
Expand Down
19 changes: 13 additions & 6 deletions src/hooks/init/twilio-api.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { Plugin } = require('@oclif/config');
const TwilioApiCommand = require('../../base-commands/twilio-api-command');
const { TwilioApiBrowser, getTopicName, TOPIC_SEPARATOR } = require('../../services/twilio-api');
const { TwilioApiBrowser, getTopicName, TOPIC_SEPARATOR, BASE_TOPIC_NAME, CORE_TOPIC_NAME } = require('../../services/twilio-api');

// Implement an oclif plugin that can provide dynamically created commands at runtime.
class TwilioRestApiPlugin extends Plugin {
Expand All @@ -12,7 +12,7 @@ class TwilioRestApiPlugin extends Plugin {

scanResource(actionDefinition) {
actionDefinition.resource = actionDefinition.version.resources[actionDefinition.path];
actionDefinition.topicName = getTopicName(actionDefinition);
actionDefinition.topicName = BASE_TOPIC_NAME + TOPIC_SEPARATOR + getTopicName(actionDefinition);
Object.keys(actionDefinition.resource.actions).forEach(actionName => {
actionDefinition.actionName = actionName;
this.scanAction(actionDefinition);
Expand All @@ -28,7 +28,7 @@ class TwilioRestApiPlugin extends Plugin {

const shortVersion = actionDefinition.versionName.replace(/v/g, '');
this.versionTopics.push({
name: actionDefinition.domainName + TOPIC_SEPARATOR + actionDefinition.versionName,
name: [BASE_TOPIC_NAME, actionDefinition.domainName, actionDefinition.versionName].join(TOPIC_SEPARATOR),
description: `version ${shortVersion} of the API`
});
}
Expand All @@ -44,8 +44,15 @@ class TwilioRestApiPlugin extends Plugin {
this.scanVersion(actionDefinition);
}, this);

let topicDomainName = domainName;

// If the domain matches our base, switch to core.
if (topicDomainName === BASE_TOPIC_NAME) {
topicDomainName = CORE_TOPIC_NAME;
}

this.domainTopics.push({
name: domainName,
name: [BASE_TOPIC_NAME, topicDomainName].join(TOPIC_SEPARATOR),
description: `resources under ${domainName}.twilio.com`
});
}
Expand All @@ -55,7 +62,7 @@ class TwilioRestApiPlugin extends Plugin {
this.apiBrowser = apiBrowser || new TwilioApiBrowser();

this.actions = [];
this.domainTopics = [];
this.domainTopics = [{ name: BASE_TOPIC_NAME, description: 'advanced access to all of the Twilio APIs' }];
this.versionTopics = [];
Object.keys(this.apiBrowser.domains).forEach(this.scanDomain, this);
}
Expand All @@ -77,7 +84,7 @@ class TwilioRestApiPlugin extends Plugin {
}

get commandIDs() {
return this.actions.map(a => a.topicName + ':' + a.commandName);
return this.actions.map(a => [a.topicName, a.commandName].join(TOPIC_SEPARATOR));
}

get commands() {
Expand Down
14 changes: 9 additions & 5 deletions src/services/twilio-api/api-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ const url = require('url');
const { doesObjectHaveProperty } = require('@twilio/cli-core').services.JSUtils;
const ResourcePathParser = require('../resource-path-parser');

const isApi2010 = (domain, version) => {
return domain === 'api' && (version === '2010-04-01' || version === 'v2010');
};

function translateLegacyVersions(domain, version) {
// In the Node helper library, api.twilio.com/2010-04-01 is represented as "v2010"
if (domain === 'api' && version === '2010-04-01') {
return 'v2010';
}
return version;
return isApi2010(domain, version) ? 'v2010' : version;
}

const listResourceMethodMap = {
Expand Down Expand Up @@ -93,4 +94,7 @@ class TwilioApiBrowser {
}
}

module.exports = TwilioApiBrowser;
module.exports = {
TwilioApiBrowser,
isApi2010
};
8 changes: 6 additions & 2 deletions src/services/twilio-api/get-topic-name.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const { kebabCase } = require('../naming-conventions');

const TOPIC_SEPARATOR = ':';
const BASE_TOPIC_NAME = 'api';
const CORE_TOPIC_NAME = 'core';

const getTopicName = actionDefinition => {
return (
Expand All @@ -12,10 +14,12 @@ const getTopicName = actionDefinition => {
.replace(/\/{.+?}/g, '') // Drop every {PathParameter}
.replace(/\/+/g, TOPIC_SEPARATOR) // Separate paths with topic separator
)
);
).replace(/api:v2010:accounts/, CORE_TOPIC_NAME); // Chop the legacy API version down
};

module.exports = {
getTopicName,
TOPIC_SEPARATOR
TOPIC_SEPARATOR,
BASE_TOPIC_NAME,
CORE_TOPIC_NAME
};
14 changes: 11 additions & 3 deletions src/services/twilio-api/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
const TwilioApiBrowser = require('./api-browser');
const { getTopicName, TOPIC_SEPARATOR } = require('./get-topic-name');
const { TwilioApiBrowser, isApi2010 } = require('./api-browser');
const { getTopicName, TOPIC_SEPARATOR, BASE_TOPIC_NAME, CORE_TOPIC_NAME } = require('./get-topic-name');
const { getActionDescription } = require('./get-action-description');

module.exports = { TwilioApiBrowser, getTopicName, TOPIC_SEPARATOR, getActionDescription };
module.exports = {
TwilioApiBrowser,
isApi2010,
getTopicName,
TOPIC_SEPARATOR,
BASE_TOPIC_NAME,
CORE_TOPIC_NAME,
getActionDescription
};
4 changes: 2 additions & 2 deletions test/base-commands/twilio-api-command.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('base-commands', () => {
test.it('setUpNewCommandClass', async () => {
const NewCommandClass = getCommandClass();

expect(NewCommandClass.id).to.equal('api:v2010:accounts:calls:create');
expect(NewCommandClass.id).to.equal('core:calls:create');
expect(NewCommandClass.description).to.contain('\'Twilio Client\' connections');
expect(NewCommandClass.load()).to.equal(NewCommandClass);

Expand All @@ -49,7 +49,7 @@ describe('base-commands', () => {
expect(NewCommandClass.flags.from.required).to.be.true;
expect(NewCommandClass.flags.method.required).to.be.false;
expect(NewCommandClass.flags.method.type).to.equal('option');
expect(NewCommandClass.flags.method.helpValue).to.eql('(head|get|post|patch|put|delete)');
expect(NewCommandClass.flags.method.helpValue).to.equal('(head|get|post|patch|put|delete)');
expect(NewCommandClass.flags.record.type).to.equal('boolean');
expect(NewCommandClass.flags.properties.default).to.equal('sid,friendlyName,status');

Expand Down
8 changes: 4 additions & 4 deletions test/hooks/init/twilio-api.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ describe('hooks', () => {
expect(plugin.commands.length).to.equal(plugin.commandIDs.length);

/* eslint-disable max-nested-callbacks */
const domainTopic = plugin.topics.find(t => t.name === 'api');
const versionTopic = plugin.topics.find(t => t.name === 'api:v2010');
const domainTopic = plugin.topics.find(t => t.name === 'api:accounts');
const versionTopic = plugin.topics.find(t => t.name === 'api:accounts:v1');

expect(domainTopic.description).to.equal('resources under api.twilio.com');
expect(versionTopic.description).to.equal('version 2010 of the API');
expect(domainTopic.description).to.equal('resources under accounts.twilio.com');
expect(versionTopic.description).to.equal('version 1 of the API');
});
});
});
Expand Down

0 comments on commit c1f87c3

Please sign in to comment.