Created
December 7, 2010 21:20
-
-
Save earth2marsh/732428 to your computer and use it in GitHub Desktop.
A WADL builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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>   | |
<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> | |
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" | |
xsi:schemaLocation="http://research.sun.com/wadl/2006/10 https://wadl.dev.java.net/wadl20061109.xsd" | |
xmlns="http://research.sun.com/wadl/2006/10"><br/> | |
<resources base="{{apiModel.host}}"><br/> | |
<label ng:repeat="resource in apiModel.resources"> | |
<resource path="{{resource.resource_path}}"><br/> | |
<label ng:repeat="param in resource.parameters"> | |
<param name="{{param.name}}" required="{{param.required|required}}" type="xsd:string" | |
style="{{param.type}}" default="{{param.value}}"/><br/> | |
</label> | |
<method name="{{resource.httpMethod}}" id="{{resource.resource_name}}"><br/> | |
<tags><br/> | |
<label ng:repeat="tag in resource.tags"> | |
<tag primary="{{tag.primary}}">{{tag.tag}}</tag><br/> | |
</label> | |
</tags><br/> | |
<authentication required="{{resource.auth_required|auth_required}}"/><br/> | |
<docs url="{{resource.docs}}><br/> | |
<label ng:repeat="url in resource.example_urls"> | |
<example url="{{url}}"/><br/> | |
</label> | |
<notes>{{resource.notes}}</notes><br/> | |
</method><br/> | |
</resource><br/> | |
</label> | |
</resources><br/> | |
</application><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