Skip to content

Instantly share code, notes, and snippets.

@earth2marsh
Created December 7, 2010 21:20
Show Gist options
  • Save earth2marsh/732428 to your computer and use it in GitHub Desktop.
Save earth2marsh/732428 to your computer and use it in GitHub Desktop.
A WADL builder
<!DOCTYPE HTML>
<html xmlns:ng="http://angularjs.org">
<head>
<script type="text/javascript"
src="http://angularjs.org/ng/js/angular-debug.js" ng:autobind></script>
</head>
<body>
<script>
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
function parseUri(str) {
var o = parseUri.options,
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
uri = {},
i = 14;
while (i--) uri[o.key[i]] = m[i] || "";
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) uri[o.q.name][$1] = $2;
});
return uri;
};
parseUri.options = {
strictMode: false,
key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
}
};
// parseUri end
function parseLine(str) {
var methodAndUrl = str.split(" "), line = {};
line.httpMethod = methodAndUrl[0];
line.uri = parseUri(methodAndUrl[1]);
return line;
};
angular.filter.required = function(req) {
return req == 'required';
};
angular.filter.auth_required = function(req) {
return req == 'auth_required';
};
function APIDescription() {
this.master = {
baseUrl: "http://api.twitter.com/v1",
resources: [
{
resource_name: 'public timeline',
resource_path: '/statuses/public_timeline.json',
httpMethod: 'GET',
parameters: [
{name: 'trim_user', required: 'false', parameterType: 'query'},
{name: 'include_entities', required: 'false', parameterType: 'query'}
],
tags: [
{ tag: 'Timeline', primary: true},
{ tag: 'Status', primary: false}
],
docs: 'http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-public_timeline',
example_urls: ['/statuses/public_timeline.json'],
notes: 'Returns the 20 most recent statuses from non-protected users who have set a custom user icon. <a href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/f881564598a947a7#">The public timeline is cached for 60 seconds</a> so requesting it more often than that is a waste of resources.',
auth_required: 'no_auth',
show: true
}
]
};
this.cancel();
/*
this.apiModel = {
baseUrl: "http://api.twitter.com/v1",
resources: [
{
resource_name: 'public timeline',
resource_path: '/statuses/public_timeline.json',
httpMethod: 'GET',
parameters: [
{name: 'trim_user', required: 'false', parameterType: 'query'},
{name: 'include_entities', required: 'false', parameterType: 'query'}
],
tags: [
{ tag: 'Timeline', primary: true},
{ tag: 'Status', primary: false}
],
docs: 'http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-public_timeline',
example_urls: ['/statuses/public_timeline.json'],
notes: 'Returns the 20 most recent statuses from non-protected users who have set a custom user icon. <a href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/f881564598a947a7#">The public timeline is cached for 60 seconds</a> so requesting it more often than that is a waste of resources.',
auth_required: 'no_auth'
}
]
};
*/
// DONT MODIFY THE TEMPLATE DIRECTLY, ALWAYS TAKE A COPY
this.api_model_template = {
baseUrl: null,
resources: []
},
this.resource_template = {
resource_name: null,
resource_path: null,
httpMethod: 'GET',
auth_required: null,
parameters: [],
tags: [],
docs: null,
example_urls: [],
notes: null,
show: true
};
}
APIDescription.prototype = {
cancel: function() {
this.apiModel = angular.copy(this.master);
},
reset: function() {
alert(localStorage.getItem('API_Description'));
this.apiModel = angular.fromJson(localStorage.getItem('API_Description'));
},
save: function() {
alert('SAVED: ' + angular.toJson(this.api));
localStorage.setItem('API_Description', angular.toJson(this.apiModel));
},
buildWADLFromBunchOfUrls: function(bunchOfUrls) {
this.apiModel = angular.copy(this.api_model_template);
var lines = bunchOfUrls.trim().split("\n");
for (var i = 0; i < lines.length; i++) {
try {
var parsedLine = parseLine(lines[i]);
var parsedUri = parsedLine.uri;
// Can we do only once??
this.apiModel.baseUrl = parsedUri.host;
// Resource definition
var resource = angular.copy(this.resource_template);
resource.resource_name = parsedUri.path.replace(/\//gi, "_");
resource.resource_path = parsedUri.path;
resource.httpMethod = parsedLine.httpMethod.toUpperCase();
resource.auth_required = 'no_auth';
resource.example_urls.push(parsedUri.source);
var queryParameters = parsedUri.queryKey;
resource.parameters = [];
for (var queryParam in queryParameters) {
var parameter = {};
parameter.name = queryParam;
parameter.type = 'string';
parameter.required = 'optional';
parameter.value = queryParameters[queryParam];
parameter.type = 'query';
resource.parameters.push(parameter);
}
this.apiModel.resources.push(resource);
} catch(e) {
alert('Error' + e);
}
}
},
buildWADLFromGoogleSMD: function(urlOrDesc) {
try {
var jsonDecs = angular.fromJson(urlOrDesc);
this.apiModel = angular.copy(this.api_model_template);
var data = jsonDecs.data;
var apiData;
for (var tmp in data) {
apiData = data[tmp];
}
var version = apiData.v1;
this.apiModel.baseUrl = version.baseUrl;
for (var r in version.resources) {
var methods = version.resources[r].methods;
for (var methodName in methods) {
var method = methods[methodName];
var resource = angular.copy(this.resource_template);
resource.resource_name = method.httpMethod;
resource.resource_path = method.pathUrl;
resource.httpMethod = method.httpMethod;
var tag = {};
resource.tags.push({tag: r, primary: true});
resource.tags.push({tag: r, primary: false});
var params = method.parameters;
resource.parameters = [];
if (params) {
for (var prop in params) {
var param = {};
param.name = prop;
param.type = 'string';
param.required = params[prop].required;
param.value = "";
param.type = params[prop].parameterType;
resource.parameters[resource.parameters.length + 1] = param;
}
}
this.apiModel.resources[this.apiModel.resources.length + 1] = resource;
}
}
} catch(e) {
alert('Failed to parse JSON' + e);
}
}
};
function testalert(source) {
source.resource.show = !source.resource.show;
};
</script>
<div ng:controller="APIDescription">
<span style="float: right;">
<button ng:click="cancel()" disabled="{{master.$equals(apiModel)}}">Cancel</button>
<button ng:click="save()" disabled="{{$invalidWidgets.visible() || master.$equals(apiModel)}}">Save</button>
</span>
<h3 align="center">API Model</h3>
<br/>
<label>API Base URL:</label>
<input size="40" type="text" name="apiModel.baseUrl"/> <br/><br/>
<label>Resources:</label>
[ <a href=""
ng:click="apiModel.resources.$add(resource_template.$copy())">Add Resource</a> ]
<br/>
<div ng:repeat="resource in apiModel.resources">
<label ng:click="$window.testalert(this)"><i>{{resource.httpMethod}} {{apiModel.baseUrl}}{{resource.resource_path}}</i> &nbsp
<b><a href="" ng:show="resource.show">[-]</a><a href="" ng:hide="resource.show">[+]</a></b>
[ <a href="" ng:click="apiModel.resources.$remove(resource)">X</a> ]
[ <a href="" ng:click="apiModel.resources.$add(resource.$copy())">Copy</a> ]
</label>
<div ng:show="resource.show">
<br/>
<select name="resource.httpMethod">
<option>GET</option>
<option>POST</option>
<option>PUT</option>
<option>DELETE</option>
<option>HEAD</option>
</select>
<input type="text" name="resource.resource_name" ng:required/>
<input type="text" size="40" name="resource.resource_path" ng:required/>
<select name="resource.auth_required">
<option>no_auth</option>
<option>auth_required</option>
</select>
<br/>
<br/>[ <a href="" ng:click="resource.parameters.$add()">Add Parameter</a> ]
<div ng:repeat="param in resource.parameters">
<select name="param.type">
<option>query</option>
<option>header</option>
</select>
<input type="text" name="param.name" value="name" ng:required/>
<select name="param.required">
<option>required</option>
<option>optional</option>
</select>
[ <a href="" ng:click="resource.parameters.$remove(param)">X</a> ]
[ <a href="" ng:click="resource.parameters.$add(param.$copy())">Copy</a> ]
</div>
<br/><label>Apigee extensions:</label>
<input type="checkbox" name="enable_apigee_extensions">
<span ng:show="enable_apigee_extensions">
[ <a href="" ng:click="resource.tags.$add()">Add Tag</a> ]
<div ng:repeat="tag in resource.tags">
<label>Tag:</label>
<input type="text" name="tag.tag" value="tag" ng:required/>
<input type="checkbox" name="tag.primary" value="false" ng:required/>
[ <a href="" ng:click="resource.tags.$remove(tag)">X</a> ]
[ <a href="" ng:click="resource.tags.$add(angular.copy(tag))">Copy</a> ]
</div>
<br/><label>Docs url:</label><input type="text" size="60" name="resource.docs" value="docs url here"/><br/>
<div ng:repeat="url in resource.example_urls">
<label>Example:</label><input type="text" size="60" name="url" value="example url here" ng:required/>[ <a href="" ng:click="resource.example_urls.$remove(url)">X</a> ][ <a href="" ng:click="resource.example_urls.$add(url)">Copy</a> ]<br/>
</div>
<br/>
<label>Notes:</label><br/><textarea type="text" name="resource.notes" value="describe resource here" cols="100" rows="5"></textarea><br/>
</span>
<span ng:hide="enable_apigee_extensions"></span>
<br/><label>
------------------------------------------------------------------------------------------------>>
<span style="float: right;">
<button ng:click="cancel()" disabled="{{master.$equals(apiModel)}}">Cancel</button>
<button ng:click="save()" disabled="{{$invalidWidgets.visible() || master.$equals(apiModel)}}">Save</button>
</span>
</label>
</div>
</div>
<br/><br/><br/>
<HR/> <HR/><HR/>
<input type="checkbox" name="build_wadl_from_urls">Build your WADL from bunch of urls like
<span ng:show="build_wadl_from_urls">
<br/><textarea name="bunchOfUrls" cols="100" rows="5"></textarea><br/>
<input type="button" value="Build API Model" ng:click="buildWADLFromBunchOfUrls(bunchOfUrls)">
</span> <br/>
<span ng:hide="build_wadl_from_urls"> GET http://api.twitter.com/statuses/public_timeline.json<br/>
GET http://api.twitter.com/statuses/home_timeline.json?trim_user=true&include_entities=true<br/>
</span> <br/>
<HR/>
<input type="checkbox" name="build_wadl_from_google_json">Build your WADL from Google's json api desc
http://www.googleapis.com/discovery/0.1/describe?api=latitude
<span ng:show="build_wadl_from_google_json">
<br/><textarea name="googleJSON" cols="100" rows="5"></textarea><br/>
<input type="button" value="Build API Model" ng:click="buildWADLFromGoogleSMD(googleJSON)">
</span> <br/>
<span ng:hide="build_wadl_from_google_json"> Google api desc <br/>
</span> <br/>
<HR/>
<!--
<button ng:click="save()">Save</button>
<button ng:click="reset()">Reset</button>
-->
<HR/>
<span>
<label><h3 align="center">WADL</h3></label><br/>
<label>
&lt;application xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;
xsi:schemaLocation=&quot;http://research.sun.com/wadl/2006/10 https://wadl.dev.java.net/wadl20061109.xsd&quot;
xmlns=&quot;http://research.sun.com/wadl/2006/10&quot;&gt;<br/>
&lt;resources base=&quot;{{apiModel.host}}&quot;&gt;<br/>
<label ng:repeat="resource in apiModel.resources">
&lt;resource path=&quot;{{resource.resource_path}}&quot;&gt;<br/>
<label ng:repeat="param in resource.parameters">
&lt;param name=&quot;{{param.name}}&quot; required=&quot;{{param.required|required}}&quot; type=&quot;xsd:string&quot;
style=&quot;{{param.type}}&quot; default=&quot;{{param.value}}&quot;/&gt;<br/>
</label>
&lt;method name=&quot;{{resource.httpMethod}}&quot; id=&quot;{{resource.resource_name}}&quot;&gt;<br/>
&lt;tags&gt;<br/>
<label ng:repeat="tag in resource.tags">
&lt;tag primary=&quot;{{tag.primary}}&quot;&gt;{{tag.tag}}&lt;/tag&gt;<br/>
</label>
&lt;/tags&gt;<br/>
&lt;authentication required=&quot;{{resource.auth_required|auth_required}}&quot;/&gt;<br/>
&lt;docs url=&quot;{{resource.docs}}&gt;<br/>
<label ng:repeat="url in resource.example_urls">
&lt;example url=&quot;{{url}}&quot;/&gt;<br/>
</label>
&lt;notes&gt;{{resource.notes}}&lt;/notes&gt;<br/>
&lt;/method&gt;<br/>
&lt;/resource&gt;<br/>
</label>
&lt;/resources&gt;<br/>
&lt;/application&gt;<br/>
</label>
</span>
<hr/>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment