Skip to content

Commit

Permalink
[DX-665] WiP for loading open api spec
Browse files Browse the repository at this point in the history
  • Loading branch information
dprothero committed Feb 7, 2019
1 parent 22d6c06 commit d441d6a
Show file tree
Hide file tree
Showing 9 changed files with 73,543 additions and 15 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ node_modules
coverage
ZORK1.DAT
*.glksave
twilio-cli-*.tgz
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ node_modules
coverage
ZORK1.DAT
*.glksave
twilio-cli-*.tgz
41 changes: 27 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,15 @@
"project": {
"description": "Manage credentials for Twilio projects."
}
},
"hooks": {
"init": "./src/hooks/init/twilio-api"
}
},
"repository": "twilio/twilio-cli",
"scripts": {
"postpack": "rimraf oclif.manifest.json npm-shrinkwrap.json",
"posttest": "eslint --ignore-path .gitignore .",
"posttest": "eslint --ignore-path .gitignore . && npm audit",
"prepack": "oclif-dev manifest && oclif-dev readme && npm shrinkwrap && git checkout -- package-lock.json",
"test": "nyc --check-coverage --lines 90 --reporter=html --reporter=text mocha --forbid-only \"test/**/*.test.js\"",
"version": "oclif-dev readme && git add README.md"
Expand Down
30 changes: 30 additions & 0 deletions src/hooks/init/twilio-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const { Plugin } = require('@oclif/config');
// const { TwilioClientCommand } = require('../../base-commands/twilio-client-command');
// const { TwilioApiBrowser } = require('../../services/twilio-api');

class TwilioRestApiPlugin extends Plugin {
async load() {
await super.load();
}

get hooks() {
return {};
}

get topics() {
return [];
}

get commandIDs() {
return [];
}

get commands() {
return [];
}
}

module.exports = async function () {
// const browser = new TwilioApiBrowser();
this.config.plugins.push(new TwilioRestApiPlugin(this.config));
};
89 changes: 89 additions & 0 deletions src/services/twilio-api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const url = require('url');
const apiSpecFromDisk = require('./twilio_api.json');

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;
}

const listResourceMethodMap = {
get: 'list',
post: 'create'
};

const instanceResourceMethodMap = {
delete: 'remove',
get: 'fetch',
post: 'update'
};

/*
Notes:
Disambiguating like-named resources:
If same resource name exists under multiple domains/versions/paths, then have the command
map to a help message when it is ambiguous as to which domain/version/path they want.
Maybe have a setting to change this behavior? Have a custom shortcut map in the config
file? Have a mode of operation where it just picks the most recent version?
*/

class TwilioApiBrowser {
constructor(apiSpec) {
this.apiSpec = apiSpec || apiSpecFromDisk;
this.domains = this.loadDomains();
}

loadDomains() {
const domains = {};

Object.keys(this.apiSpec.paths).forEach(path => {
// Naive assumption: The Twilio API's only have a single domain
const serverUrl = new url.URL(this.apiSpec.paths[path].servers[0].url);
const domain = serverUrl.host.split('.')[0]; // e.g. 'api' from 'api.twilio.com'

const version = translateLegacyVersions(
domain,
path.split('/')[1] // e.g. 'v1' from '/v1/foo/bar'
);

if (!Object.prototype.hasOwnProperty.call(domains, domain)) {
domains[domain] = { versions: {} };
}

if (!Object.prototype.hasOwnProperty.call(domains[domain].versions, version)) {
domains[domain].versions[version] = { resources: {} };
}

const isInstanceResource = path.endsWith('}.json');

const pathParts = path.split('/');
pathParts.splice(1, 1); // e.g. '/v1/foo' becomes '/foo'
if (isInstanceResource) {
pathParts.splice(pathParts.length - 1, 1); // e.g. /foo/{Sid} becomes /foo
}
const resourcePath = pathParts.join('/').replace('.json', '');

const resources = domains[domain].versions[version].resources;
if (!Object.prototype.hasOwnProperty.call(resources, resourcePath)) {
resources[resourcePath] = { actions: {} };
}

const actions = resources[resourcePath].actions;
const methodMap = isInstanceResource ? instanceResourceMethodMap : listResourceMethodMap;
Object.keys(methodMap).forEach(method => {
if (Object.prototype.hasOwnProperty.call(this.apiSpec.paths[path], method)) {
actions[methodMap[method]] = this.apiSpec.paths[path][method];
}
});
});

return domains;
}
}

module.exports = { TwilioApiBrowser };
Loading

0 comments on commit d441d6a

Please sign in to comment.