yay: dev complete: swagger javascript sandbox

This commit is contained in:
Ayush Gupta
2011-07-28 16:35:05 -07:00
parent cde87fbddf
commit 2a6ed09f74
8 changed files with 158 additions and 64 deletions

View File

@@ -94,69 +94,66 @@
<script id="apiTemplate" type="text/x-jquery-tmpl">
<li class='endpoint'>
<ul id='${name}_endpoint_${id}_operations' class='operations'>
<ul id='${name}_endpoint_operations' class='operations'>
</ul>
</li>
</script>
<script id="operationTemplate" type="text/x-jquery-tmpl">
<li class='${httpMethodLowercase} operation' id='${apiName}_${nickname}_${id}'>
<li class='${httpMethodLowercase} operation' id='${apiName}_${nickname}_${httpMethod}'>
<div class='heading'>
<h3>
<span class='http_method'><a href="#!/${apiName}/${nickname}_${id}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${id}_content');">${httpMethod}</a></span>
<span class='path'><a href="#!/${apiName}/${nickname}_${id}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${id}_content');">${path_json}</a></span>
<span class='http_method'><a href="#!/${apiName}/${nickname}_${httpMethod}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${httpMethod}_content');">${httpMethod}</a></span>
<span class='path'><a href="#!/${apiName}/${nickname}_${httpMethod}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${httpMethod}_content');">${path_json}</a></span>
</h3>
<ul class='options'>
<li><a href="#!/${apiName}/${nickname}_${id}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${id}_content');">${summary}</a></li>
<li><a href="#!/${apiName}/${nickname}_${httpMethod}"
onclick="Docs.toggleOperationContent('${apiName}_${nickname}_${httpMethod}_content');">${summary}</a></li>
</ul>
</div>
<div class='content' id='${apiName}_${nickname}_${id}_content' style='display:none'>
<form id="${apiName}_${nickname}_${id}_form" accept-charset="UTF-8" action="#" class="sandbox" method="post">
<div class='content' id='${apiName}_${nickname}_${httpMethod}_content' style='display:none'>
<form id="${apiName}_${nickname}_${httpMethod}_form" accept-charset="UTF-8" action="#" class="sandbox" method="post">
<div style="margin:0;padding:0;display:inline"></div>
<h4>Parameters</h4>
<table class='fullwidth'>
<thead>
<tr>
<th>Parameter</th>
<th id="${apiName}_${nickname}_${id}_value_header">Value</th>
<th id="${apiName}_${nickname}_${httpMethod}_value_header">Value</th>
<th>Description</th>
</tr>
</thead>
<tbody id="${apiName}_${nickname}_${id}_params">
<tbody id="${apiName}_${nickname}_${httpMethod}_params">
</tbody>
</table>
<div class='sandbox_header' id='${apiName}_${nickname}_${id}_content_sandbox_response_header'>
<input class="submit" id="${apiName}_${nickname}_${id}_content_sandbox_response_button" name="commit"
<div class='sandbox_header' id='${apiName}_${nickname}_${httpMethod}_content_sandbox_response_header'>
<input class="submit" id="${apiName}_${nickname}_${httpMethod}_content_sandbox_response_button" name="commit"
type="button" value="Try it out!"/>
<a href="#" id="${apiName}_${nickname}_${id}_content_sandbox_response_hider"
onclick="$('#${apiName}_${nickname}_${id}_content_sandbox_response').slideUp();$(this).fadeOut(); return false;"
<a href="#" id="${apiName}_${nickname}_${httpMethod}_content_sandbox_response_hider"
onclick="$('#${apiName}_${nickname}_${httpMethod}_content_sandbox_response').slideUp();$(this).fadeOut(); return false;"
style="display:none">Hide Response</a>
<img alt="Throbber" id="${apiName}_${nickname}_${id}_content_sandbox_response_throbber"
<img alt="Throbber" id="${apiName}_${nickname}_${httpMethod}_content_sandbox_response_throbber"
src="images/throbber.gif" style="display:none"/>
</div>
</form>
<div class='response' id='${apiName}_${nickname}_${id}_content_sandbox_response' style='display:none'>
<div class='response' id='${apiName}_${nickname}_${httpMethod}_content_sandbox_response' style='display:none'>
<h4>Request URL</h4>
<div class='block request_url'></div>
<h4>Response Body</h4>
<div class='block response_body'></div>
<h4>Response Code</h4>
<div class='block response_code'></div>
<h4>Response Headers</h4>
<div class='block response_headers'></div>
<h4>Example Ruby Request</h4>
<div class='block response_ruby_example'></div>
</div>
</div>
</li>
@@ -166,7 +163,7 @@
<script id="paramTemplateRequired" type="text/x-jquery-tmpl">
<tr>
<td class='code required'>${name}</td>
<td><input id="${name}_${id}" name="${name}" class="required" minlength="1" placeholder="(required)" type="text" value=""/></td>
<td><input name="${name}" class="required" minlength="1" placeholder="(required)" type="text" value=""/></td>
<td width='500'><strong>${description}</strong>
</td>
</tr>
@@ -175,7 +172,7 @@
<script id="paramTemplate" type="text/x-jquery-tmpl">
<tr>
<td class='code'>${name}</td>
<td><input id="${name}_${id}" name="${name}" class="" minlength="0" placeholder="" type="text" value=""/></td>
<td><input name="${name}" class="" minlength="0" placeholder="" type="text" value=""/></td>
<td width='500'>${description}</td>
</tr>
</script>

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
jQuery(function(h){var a=Spine.Controller.create({baseUrlList:new Array(),init:function(){if(this.supportsLocalStorage()){var i=localStorage.getItem("com.wordnik.swagger.ui.baseUrls");if(i&&jQuery.trim(i).length>0){this.baseUrlList=i.split(",")}}else{log("local storage not supported, user will need to specifiy the api url")}this.render()},supportsLocalStorage:function(){try{return"localStorage" in window&&window.localStorage!==null}catch(i){return false}},render:function(){h("#baseUrlSelector").chosen()}});var g=Spine.Controller.create({proxied:["addAll","addOne"],ApiResource:null,init:function(){if(this.baseUrl==null){throw new Error("A baseUrl must be passed to ResourceListController")}var j=this.baseUrl.substr(0,this.baseUrl.lastIndexOf("/"));var k=this.baseUrl.substr(this.baseUrl.lastIndexOf("/")+1,this.baseUrl.length);log("resourceListApi="+k);log("hostUrl="+j);h("#api_host_url").html(j);var i=new SwaggerService(j,"list");i.init();this.ApiResource=i.ApiResource();this.ApiResource.bind("refresh",this.addAll)},addAll:function(){this.ApiResource.each(this.addOne)},addOne:function(i){e.init({item:i,container:"#resources"})}});var e=Spine.Controller.create({proxied:["renderApi","renderOperation"],templateName:"#resourceTemplate",apiResource:null,apiList:null,modelList:null,init:function(){this.render();this.apiResource=this.item;this.apiList=this.apiResource.apiList;this.modelList=this.apiResource.modelList;this.apiList.each(this.renderApi)},render:function(){h(this.templateName).tmpl(this.item).appendTo(this.container)},renderApi:function(j){var i="#"+this.apiResource.name+"_endpoint_list";d.init({item:j,container:i})}});var d=Spine.Controller.create({proxied:["renderOperation"],api:null,templateName:"#apiTemplate",init:function(){this.render();this.api=this.item;this.api.operations.each(this.renderOperation)},render:function(){h(this.templateName).tmpl(this.item).appendTo(this.container)},renderOperation:function(i){var j="#"+this.api.name+"_endpoint_"+this.api.id+"_operations";c.init({item:i,container:j})}});var c=Spine.Controller.create({proxied:["submitOperation"],operation:null,templateName:"#operationTemplate",elementScope:"#operationTemplate",init:function(){this.render();this.operation=this.item;this.isGetOperation=(this.operation.httpMethodLowercase=="get");this.elementScope="#"+this.operation.apiName+"_"+this.operation.nickname+"_"+this.operation.id;this.renderParams()},render:function(){h(this.templateName).tmpl(this.item).appendTo(this.container)},renderParams:function(){if(this.operation.parameters&&this.operation.parameters.count()>0){var k=this.elementScope+"_params";log("operationParamsContainer = "+k);for(var l=0;l<this.operation.parameters.count();l++){var m=this.operation.parameters.all()[l];var i="#paramTemplate";if(m.required){i+="Required"}if(!this.isGetOperation){i+="ReadOnly"}h(i).tmpl(m).appendTo(k)}}var j=this.elementScope+"_content_sandbox_response_button";if(this.isGetOperation){h(j).click(this.submitOperation)}else{h(j).hide();var n=this.elementScope+"_value_header";h(n).html("Default Value")}},submitOperation:function(){var k=h(this.elementScope+"_form");var j=true;var i=null;k.find("input.required").each(function(){h(this).removeClass("error");if(h(this).val()==""){if(i==null){i=h(this)}h(this).addClass("error");h(this).wiggle();j=false}});log("error_free = "+j)}});var b=a.init();var f=g.init({baseUrl:"http://swagr.api.wordnik.com/v4/list.json"})});
jQuery(function(e){this.baseUrl="http://swagr.api.wordnik.com/v4/list.json";var f=Spine.Controller.create({proxied:["showApi"],baseUrlList:new Array(),init:function(){if(this.supportsLocalStorage()){var k=localStorage.getItem("com.wordnik.swagger.ui.baseUrls");if(k&&jQuery.trim(k).length>0){this.baseUrlList=k.split(",")}}else{log("local storage not supported, user will need to specifiy the api url")}this.render();e("#button_explore").click(this.showApi)},slapOn:function(){i.showMessage("Please enter a base url for the api that you wish to explore.");e("#resources_container").hide()},supportsLocalStorage:function(){try{return"localStorage" in window&&window.localStorage!==null}catch(k){return false}},render:function(){},showApi:function(){var l=jQuery.trim(e("#input_baseUrl").val());var m=jQuery.trim(e("#input_apiKey").val());if(l.length==0){e("#input_baseUrl").wiggle()}else{var k=a.init({baseUrl:l,apiKey:m})}}});var b=Spine.Controller.create({showMessage:function(k){if(k){e("#content_message").html(k);e("#content_message").show()}else{e("#content_message").html("");e("#content_message").hide()}},clearMessage:function(){this.showMessage()}});var i=b.init();var a=Spine.Controller.create({proxied:["addAll","addOne"],ApiResource:null,init:function(){if(this.baseUrl==null){throw new Error("A baseUrl must be passed to ResourceListController")}e("#content_message").hide();e("#resources_container").hide();e("#resources").html("");e("#api_host_url").html(this.baseUrl);var k=new SwaggerService(this.baseUrl,this.apiKey,function(l){if(l){i.showMessage(l)}else{i.showMessage("Rendering page...")}});k.init();this.ApiResource=k.ApiResource();this.ApiResource.bind("refresh",this.addAll)},addAll:function(){this.ApiResource.each(this.addOne);i.clearMessage();e("#resources_container").slideDown();setTimeout(function(){Docs.shebang()},1000)},addOne:function(k){d.init({item:k,container:"#resources"})}});var d=Spine.Controller.create({proxied:["renderApi","renderOperation"],templateName:"#resourceTemplate",apiResource:null,apiList:null,modelList:null,init:function(){this.render();this.apiResource=this.item;this.apiList=this.apiResource.apiList;this.modelList=this.apiResource.modelList;this.apiList.each(this.renderApi)},render:function(){e(this.templateName).tmpl(this.item).appendTo(this.container)},renderApi:function(l){var k="#"+this.apiResource.name+"_endpoint_list";h.init({item:l,container:k})}});var h=Spine.Controller.create({proxied:["renderOperation"],api:null,templateName:"#apiTemplate",init:function(){this.render();this.api=this.item;this.api.operations.each(this.renderOperation)},render:function(){e(this.templateName).tmpl(this.item).appendTo(this.container)},renderOperation:function(k){var l="#"+this.api.name+"_endpoint_operations";c.init({item:k,container:l})}});var c=Spine.Controller.create({proxied:["submitOperation","showResponse"],operation:null,templateName:"#operationTemplate",elementScope:"#operationTemplate",init:function(){this.render();this.operation=this.item;this.isGetOperation=(this.operation.httpMethodLowercase=="get");this.elementScope="#"+this.operation.apiName+"_"+this.operation.nickname+"_"+this.operation.httpMethod;this.renderParams()},render:function(){e(this.templateName).tmpl(this.item).appendTo(this.container)},renderParams:function(){if(this.operation.parameters&&this.operation.parameters.count()>0){var m=this.elementScope+"_params";for(var n=0;n<this.operation.parameters.count();n++){var o=this.operation.parameters.all()[n];var k="#paramTemplate";if(o.required){k+="Required"}if(!this.isGetOperation){k+="ReadOnly"}e(k).tmpl(o).appendTo(m)}}var l=this.elementScope+"_content_sandbox_response_button";if(this.isGetOperation){e(l).click(this.submitOperation)}else{e(l).hide();var q=this.elementScope+"_value_header";e(q).html("Default Value")}},submitOperation:function(){var m=e(this.elementScope+"_form");var l=true;var k=null;m.find("input.required").each(function(){e(this).removeClass("error");if(e(this).val()==""){if(k==null){k=e(this)}e(this).addClass("error");e(this).wiggle();l=false}});log("error_free = "+l);if(l){var n=this.operation.invocationUrl(m.serializeArray());e.getJSON(n,this.showResponse)}},showResponse:function(k){log(k);var l=JSON.stringify(k,null,"\t");log(l);e(".response_body",this.elementScope+"_content_sandbox_response").html(l);e(this.elementScope+"_content_sandbox_response").slideDown()}});var g=f.init();if(this.baseUrl){var j=a.init({baseUrl:this.baseUrl,apiKey:this.apiKey})}else{g.slapOn()}});

View File

@@ -49,9 +49,6 @@ $(function() {
return error_free;
});
// Handle URL fragments
Docs.shebang();
});
function clippyCopiedCallback(a) {
@@ -91,9 +88,17 @@ var Docs = {
// Refer to the endpoint DOM element, e.g. #words_get_search
log('shebang endpoint: ' + fragments.join('_'));
// Expand Resource
Docs.expandEndpointListForResource(fragments[0]);
$("#"+dom_id).slideto({highlight: false});
// Expand operation
var li_dom_id = fragments.join('_');
var li_content_dom_id = li_dom_id + "_content";
log("li_dom_id " + li_dom_id);
log("li_content_dom_id " + li_content_dom_id);
Docs.expandOperation($('#'+li_content_dom_id));
$('#'+li_dom_id).slideto({highlight: false});
break;

View File

@@ -1,6 +1,6 @@
jQuery(function($) {
// create and initialize SwaggerService
var swaggerService = new SwaggerService("http://swagr.api.wordnik.com/v4");
var swaggerService = new SwaggerService("http://swagr.api.wordnik.com/v4/list.json");
swaggerService.init();
// Create convenience references to Spine models

View File

@@ -1,12 +1,34 @@
function SwaggerService(hostUrl, rootResourcesApi, statusCallback) {
if(!hostUrl)
throw new Error("hostUrl must be passed while creating SwaggerService");
function SwaggerService(baseUrl, _apiKey, statusCallback) {
if(!baseUrl)
throw new Error("baseUrl must be passed while creating SwaggerService");
// constants
var apiHost = hostUrl;
var rootResourcesApiName = rootResourcesApi || "list";
baseUrl = jQuery.trim(baseUrl);
if(baseUrl.length == 0)
throw new Error("baseUrl must be passed while creating SwaggerService");
if(!(baseUrl.toLowerCase().indexOf("http:") == 0 || baseUrl.toLowerCase().indexOf("https:") == 0)) {
baseUrl = ("http://" + baseUrl);
}
log("using base url " + baseUrl);
var apiHost = baseUrl.substr(0, baseUrl.lastIndexOf("/"));
var rootResourcesApiName = baseUrl.substr(baseUrl.lastIndexOf("/") + 1, (baseUrl.lastIndexOf(".") - baseUrl.lastIndexOf("/") - 1));
var statusListener = statusCallback;
var apiKey = _apiKey;
var apiKeySuffix = "";
if(apiKey) {
apiKey = jQuery.trim(apiKey);
if(apiKey.length > 0)
apiKeySuffix = "?api_key=" + apiKey;
}
log("apiHost=" + apiHost);
log("apiKey=" + apiKey);
log("rootResourcesApiName = " + rootResourcesApiName);
// utility functions
function log(m) {
@@ -148,6 +170,37 @@ function SwaggerService(hostUrl, rootResourcesApi, statusCallback) {
paramsString += ")";
return "{" + this.path_json + "| " + this.nickname + paramsString + ": " + this.summary + "}";
},
invocationUrl: function(formValues) {
var formValuesMap = new Object();
for (var i = 0; i < formValues.length; i++) {
var formValue = formValues[i];
if(formValue.value && jQuery.trim(formValue.value).length > 0)
formValuesMap[formValue.name] = formValue.value;
}
var urlTemplateText = this.path_json.split("{").join("${");
log("url template = " + urlTemplateText);
var urlTemplate = $.template(null, urlTemplateText);
var url = $.tmpl(urlTemplate, formValuesMap)[0].data;
log("url with path params = " + url);
var queryParams = apiKeySuffix;
this.parameters.each(function (param) {
var paramValue = jQuery.trim(formValuesMap[param.name]);
if(param.paramType == "query" && paramValue.length > 0) {
queryParams += queryParams.length > 0 ? "&" : "?";
queryParams += param.name;
queryParams += "=";
queryParams += formValuesMap[param.name];
}
});
url = this.baseUrl + url + queryParams;
log("final url with query params and base url = " + url);
return url;
}
});
@@ -267,10 +320,14 @@ function SwaggerService(hostUrl, rootResourcesApi, statusCallback) {
var controller = this;
updateStatus("Fetching API List...");
$.getJSON(apiHost + "/" + rootResourcesApiName + ".json", function(response) {
$.getJSON(apiHost + "/" + rootResourcesApiName + ".json" + apiKeySuffix, function(response) {
//log(response);
ApiResource.createAll(response.apis);
ApiResource.findByAttribute("name", rootResourcesApiName).destroy();
// get rid of the root resource list api since we're not going to document that
var obj = ApiResource.findByAttribute("name", rootResourcesApiName);
if(obj)
obj.destroy();
controller.fetchResources();
@@ -290,7 +347,7 @@ function SwaggerService(hostUrl, rootResourcesApi, statusCallback) {
fetchResource: function(apiResource) {
var controller = this;
updateStatus("Fetching " + apiResource.name + "...");
$.getJSON(apiHost + apiResource.path_json, function(response) {
$.getJSON(apiHost + apiResource.path_json + apiKeySuffix, function(response) {
controller.loadResources(response, apiResource);
});
},

View File

@@ -1,6 +1,7 @@
jQuery(function($) {
this.baseUrl = "http://swagr.api.wordnik.com/v4/list.json";
// this.apiKey = "my-api-key";
var ApiSelectionController = Spine.Controller.create({
proxied: ["showApi"],
@@ -42,10 +43,12 @@ jQuery(function($) {
showApi: function() {
var baseUrl = jQuery.trim($("#input_baseUrl").val());
var apiKey = jQuery.trim($("#input_apiKey").val());
if (baseUrl.length == 0) {
$("#input_baseUrl").wiggle();
} else {
var resourceListController = ResourceListController.init({baseUrl: baseUrl})
var resourceListController = ResourceListController.init({baseUrl: baseUrl, apiKey: apiKey})
}
}
});
@@ -88,14 +91,9 @@ jQuery(function($) {
$("#resources_container").hide();
$("#resources").html("");
var hostUrl = this.baseUrl.substr(0, this.baseUrl.lastIndexOf("/"));
var resourceListApi = this.baseUrl.substr(this.baseUrl.lastIndexOf("/") + 1, this.baseUrl.length);
log("resourceListApi=" + resourceListApi);
log("hostUrl=" + hostUrl);
// create and initialize SwaggerService
$("#api_host_url").html(hostUrl);
var swaggerService = new SwaggerService(hostUrl, "list", function(msg) {
$("#api_host_url").html(this.baseUrl);
var swaggerService = new SwaggerService(this.baseUrl, this.apiKey, function(msg) {
if (msg)
messageController.showMessage(msg);
else
@@ -112,7 +110,11 @@ jQuery(function($) {
addAll: function() {
this.ApiResource.each(this.addOne);
messageController.clearMessage();
$("#resources_container").slideDown();
$("#resources_container").slideDown(function() {
setTimeout(function() {
Docs.shebang();
}, 400)
});
},
addOne: function(apiResource) {
@@ -175,13 +177,13 @@ jQuery(function($) {
},
renderOperation: function(operation) {
var operationsContainer = "#" + this.api.name + "_endpoint_" + this.api.id + "_operations";
var operationsContainer = "#" + this.api.name + "_endpoint_operations";
OperationController.init({item: operation, container: operationsContainer});
}
});
var OperationController = Spine.Controller.create({
proxied: ["submitOperation"],
proxied: ["submitOperation", "showResponse", "showErrorStatus", "showCompleteStatus"],
operation: null,
templateName: "#operationTemplate",
@@ -192,7 +194,7 @@ jQuery(function($) {
this.operation = this.item;
this.isGetOperation = (this.operation.httpMethodLowercase == "get");
this.elementScope = "#" + this.operation.apiName + "_" + this.operation.nickname + "_" + this.operation.id;
this.elementScope = "#" + this.operation.apiName + "_" + this.operation.nickname + "_" + this.operation.httpMethod;
this.renderParams();
@@ -205,7 +207,7 @@ jQuery(function($) {
renderParams: function() {
if (this.operation.parameters && this.operation.parameters.count() > 0) {
var operationParamsContainer = this.elementScope + "_params";
log("operationParamsContainer = " + operationParamsContainer);
// log("operationParamsContainer = " + operationParamsContainer);
for (var p = 0; p < this.operation.parameters.count(); p++) {
var param = this.operation.parameters.all()[p];
@@ -235,7 +237,6 @@ jQuery(function($) {
submitOperation: function() {
var form = $(this.elementScope + "_form");
var error_free = true;
var missing_input = null;
@@ -258,7 +259,40 @@ jQuery(function($) {
log("error_free = " + error_free);
if (error_free) {
var invocationUrl = this.operation.invocationUrl(form.serializeArray());
$(".request_url", this.elementScope + "_content_sandbox_response").html("<pre>" + invocationUrl + "</pre>");
$.getJSON(invocationUrl, this.showResponse).complete(this.showCompleteStatus).error(this.showErrorStatus);
}
},
showResponse: function(response) {
// log(response);
var prettyJson = JSON.stringify(response, null, '\t');
// log(prettyJson);
$(".response_body", this.elementScope + "_content_sandbox_response").html("<pre>" + prettyJson + "</pre>");
$(this.elementScope + "_content_sandbox_response").slideDown();
},
showErrorStatus: function(data) {
log("error " + data.status);
this.showStatus(data);
},
showCompleteStatus: function(data) {
log("complete " + data.status);
this.showStatus(data);
},
showStatus: function(data) {
log(data);
log(data.getAllResponseHeaders());
$(".response_code", this.elementScope + "_content_sandbox_response").html("<pre>" + data.status + "</pre>");
$(".response_headers", this.elementScope + "_content_sandbox_response").html("<pre>" + data.getAllResponseHeaders() + "</pre>");
}
});
@@ -266,7 +300,7 @@ jQuery(function($) {
var apiSelectionController = ApiSelectionController.init();
if (this.baseUrl) {
var resourceListController = ResourceListController.init({baseUrl: this.baseUrl});
var resourceListController = ResourceListController.init({baseUrl: this.baseUrl, apiKey: this.apiKey});
} else {
apiSelectionController.slapOn();
}

View File

@@ -0,0 +1 @@
.header-input:focus{outline:1px none;border:#ccc solid 1px}.header-input{border:#969696 solid 1px;margin-top:4px;padding-left:2px;height:20px;resize:none;color:#eee;font-size:14px;background:#666}