Created
August 16, 2012 02:41
-
-
Save jrbasso/3365894 to your computer and use it in GitHub Desktop.
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 lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>API Web Runner</title> | |
<link href="bootstrap20/css/bootstrap.min.css" rel="stylesheet" /> | |
<link href="bootstrap20/css/bootstrap-responsive.min.css" rel="stylesheet" /> | |
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/themes/redmond/jquery-ui.css" rel="stylesheet" /> | |
<style type="text/css"> | |
/* Override some defaults */ | |
body { | |
padding-top: 50px; /* 40px to make the container go all the way to the bottom of the topbar */ | |
} | |
.container > footer p { | |
text-align: center; /* center align it with the container */ | |
} | |
.container { | |
width: 820px; /* downsize our container to make the content feel a bit tighter and more cohesive. NOTE: this removes two full columns from the grid, meaning you only go to 14 columns and not 16. */ | |
} | |
.ui-menu-item > a > small { | |
font-size: 10px; | |
} | |
.ui-menu-item { | |
border-bottom: 1px solid black; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="navbar navbar-fixed-top"> | |
<div class="navbar-inner"> | |
<div class="container"> | |
<a class="brand" href="#">API Web Runner</a> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<header> | |
<h1>API Web Runner</h1> | |
<p>Simple interface to make requests to interal API.</p> | |
</header> | |
<div class="row"> | |
<form class="well"> | |
<div class="row"> | |
<div class="span1"> | |
<label for="request-method">Method</label> | |
<select id="request-method" class="span1"> | |
<option value="GET">GET</option> | |
<option value="POST">POST</option> | |
<option value="PUT">PUT</option> | |
<option value="DELETE">DELETE</option> | |
</select> | |
</div> | |
<div class="span4"> | |
<label for="request-url">URL</label> | |
<input id="request-url" type="text" class="span4" placeholder="Type the URL starting with slash"> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="span1"> | |
<label>Locale</label> | |
<input id="request-locale" type="text" class="span1" value="en-US"> | |
</div> | |
<div class="span6"> | |
<label>Requester Username</label> | |
<input id="request-username" type="text" class="span3"> | |
<span class="help-inline">Leave empty for anonymous request</span> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="span7"> | |
<table id="request-params" class="table table-striped"> | |
<thead> | |
<tr> | |
<th>Parameter</th> | |
<th>Value</th> | |
<th>Action</th> | |
</tr> | |
</thead> | |
<tbody></tbody> | |
</table> | |
<button id="request-add-param" class="btn">Add Param</button> | |
</div> | |
</div> | |
<br><br> | |
<button id="request-submit" type="submit" class="btn">Request</button> | |
</form> | |
<div id="response" class="well" style="display: none"> | |
<h2>Response</h2> | |
<p>Code: <span id="response-code">0</span></p> | |
<pre id="response-body"></pre> | |
</div> | |
<div id="response-log" class="well" style="display: none"> | |
<h2>Log messages</h2> | |
<table id="response-log-messages" class="table table-striped"> | |
<thead> | |
<tr> | |
<th>Message</th> | |
<th>Type</th> | |
<th>Data</th> | |
</tr> | |
</thead> | |
<tbody> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
<footer> | |
<p>© Foo Bar Company</p> | |
</footer> | |
</div> | |
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script> | |
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.min.js"></script> | |
<script type="text/javascript" src="bootstrap20/js/bootstrap.min.js"></script> | |
<script type="text/javascript"> | |
var searchList = { | |
GET: [], | |
POST: [], | |
PUT: [], | |
DELETE: [] | |
}; | |
function buildUriRegex(uri, params) { | |
// Convert the URI to RegExp string | |
for (var param in params) { | |
uri = uri.replace('/' + params[param].toUpperCase(), '/(.+)'); | |
} | |
// Extract the pieces and transform variables in RegExp objects | |
var pieces = uri.substring(1).split('/'); | |
for (piece in pieces) { | |
if (pieces[piece] === '(.+)') { | |
pieces[piece] = new RegExp(pieces[piece]); | |
} | |
} | |
return pieces; | |
} | |
function buildSearch(data) { | |
var controller, method; | |
if (!data.data) { | |
return; | |
} | |
for (var controllerIndex in data.data) { | |
controller = data.data[controllerIndex]; | |
for (var methodIndex in controller) { | |
method = controller[methodIndex]; | |
searchList[method.http_method].push({ | |
uri: method.uri, | |
uriParams: method.params, | |
uriRegex: buildUriRegex(method.uri, method.params), | |
description: method.doc_comment.description || '', | |
params: method.doc_comment.tags.postParam || method.doc_comment.tags.inputParam || {} | |
}); | |
} | |
} | |
enableAutocomplete(); | |
} | |
function enableAutocomplete() { | |
var $url = $('#request-url'); | |
$url.autocomplete({ | |
source: function(criteria, response) { | |
var SUGGESTION_LIMIT = 8, | |
method = $('#request-method').val(), | |
userUrl = criteria.term, | |
userUrlPieces = userUrl.substring(1).split('/'), | |
uris = [], | |
searchMethod; | |
// Ignore empty or just / | |
if (userUrl.length < 2) { | |
return; | |
} | |
// Remove the last element if it is empty | |
if (userUrlPieces[userUrlPieces.length - 1] == "") { | |
userUrlPieces.pop(); | |
} | |
loopMethods: | |
for (var i in searchList[method]) { | |
var userPiecesLength = userUrlPieces.length; | |
searchMethod = searchList[method][i]; | |
// Ignore if the number of pieces in method is lesser than user input | |
if (searchMethod.uriRegex.length < userPiecesLength) { | |
continue; | |
} | |
loopUserPieces: | |
for (var userPieceIndex in userUrlPieces) { | |
var methodPiece = searchMethod.uriRegex[userPieceIndex], | |
userPiece = userUrlPieces[userPieceIndex]; | |
// Just need to validate the strings, the objects will always match | |
if (typeof(methodPiece) === 'string') { | |
if (userPieceIndex == userPiecesLength - 1) { | |
// Last piece can be partial | |
if (methodPiece.substring(0, userPiece.length) != userPiece) { | |
continue loopMethods; | |
} | |
} else if (methodPiece != userPiece) { | |
continue loopMethods; | |
} | |
} | |
} | |
// Nothing else against add the uri in the list | |
uris.push({ | |
label: searchMethod.uri, | |
value: i, | |
method: searchMethod | |
}); | |
if (uris.length >= SUGGESTION_LIMIT) { | |
break; | |
} | |
} | |
response(uris); | |
}, | |
focus: function(event, ui) { | |
// Do not change the input field while selecting | |
return false; | |
}, | |
select: function(event, ui) { | |
// Let's make a mess with the user url | |
var $url = $('#request-url'), | |
userPieces = $url.val().substring(1).split('/'), | |
userPiecesLength = userPieces.length, | |
method = ui.item.method, | |
newUrl = ''; | |
if (method.uriParams.length == 0) { | |
newUrl = method.uri; | |
} else { | |
var paramPos = 0; | |
for (var i in method.uriRegex) { | |
if (typeof(method.uriRegex[i]) === 'string') { | |
newUrl += '/' + method.uriRegex[i]; | |
} else { | |
newUrl += '/' + (userPieces[i] || method.uriParams[paramPos].toUpperCase()); | |
paramPos++; | |
} | |
} | |
} | |
$url.val(newUrl); | |
// Set the params | |
cleanParams(); | |
for (var key in ui.item.method.params) { | |
addParam(key, '', ui.item.method.params[key].description, ui.item.method.params[key].optional); | |
} | |
return false; | |
} | |
}).data('autocomplete')._renderItem = function (ul, item) { | |
return $('<li></li>') | |
.data('item.autocomplete', item) | |
.append('<a><strong>' + item.method.uri + '</strong><br><small>' + item.method.description + '</small></a>') | |
.appendTo(ul); | |
}; | |
} | |
function loadDefaultParams() { | |
var urlParams = {}; | |
(function () { | |
var match, | |
pl = /\+/g, // Regex for replacing addition symbol with a space | |
search = /([^&=]+)=?([^&]*)/g, | |
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, | |
query = window.location.search.substring(1); | |
while (match = search.exec(query)) { | |
urlParams[decode(match[1])] = decode(match[2]); | |
} | |
})(); | |
if (urlParams['method']) { | |
$('#request-method').val(urlParams['method']); | |
} | |
if (urlParams['uri']) { | |
$('#request-url').val(urlParams['uri']); | |
} | |
} | |
function getSubmitParams() { | |
var params = {}; | |
$('#request-params > tbody > tr').each(function(index) { | |
var name = $(this).find('.request-param-name').val(), | |
value = $(this).find('.request-param-value').val(); | |
if (!name) { | |
return; | |
} | |
params[name] = value; | |
}); | |
return params; | |
} | |
function cleanParams() { | |
$('#request-params > tbody').html(''); | |
} | |
function addParam(key, value, help, optional) { | |
var $paramRows = $('#request-params > tbody'), | |
tr; | |
if (optional === false) { | |
help = '<i class="icon-exclamation-sign"></i> ' + help; | |
} | |
tr = '<tr>'; | |
tr += '<td><input class="request-param-name span2" value="' + key + '"></td>'; | |
tr += '<td><input class="request-param-value span4" value="' + value + '"><span class="help-block">' + help + '</span></td>'; | |
tr += '<td><a href="#" class="request-param-remove">Remove</td>'; | |
tr += '</tr>'; | |
$paramRows.append(tr); | |
} | |
function serviceRequest(url) { | |
var serviceRequest, headers = {}; | |
// Set the headers | |
if ($('#request-locale').val()) { | |
headers['Accept-Language'] = $('#request-locale').val(); | |
} | |
if ($('#request-username').val()) { | |
headers['X-Requested-Username'] = $('#request-username').val(); | |
} | |
headers['Accept'] = 'application/vnd.custom.api-v1.0'; | |
serviceRequest = $.ajax({ | |
type: $('#request-method').val(), | |
url: url, | |
cache: false, | |
headers: headers, | |
data: getSubmitParams() | |
}).always(function(data, status) { | |
parseServiceResponse(serviceRequest, status, data); | |
parseServiceResponseLog(serviceRequest); | |
}); | |
} | |
function parseServiceResponse(xhr, status, data) { | |
$('#response').show(); | |
$('#response-code').text(xhr.status + " (" + xhr.statusText + ")"); | |
if (status !== "success") { | |
data = JSON.parse(data.responseText); | |
} | |
$('#response-body').text(JSON.stringify(data, null, 4)); | |
} | |
function parseServiceResponseLog(xhr) { | |
var log = xhr.getResponseHeader('X-ChromePhp-Data'); | |
if (!log) { | |
$('#response-log').hide(); | |
return; | |
} | |
var tableRows = $('#response-log-messages > tbody'); | |
$('#response-log').show(); | |
tableRows.html(''); | |
log = JSON.parse(atob(log)); | |
for (var i in log.rows) { | |
var row = log.rows[i], | |
tr; | |
tr = '<tr><td>' + row[0] + '</td><td>' + row[3] + '</td>'; | |
tr = tr + '<td><pre>' + JSON.stringify(row[1], null, 4) + '</pre></td></tr>'; | |
tableRows.append(tr); | |
} | |
} | |
$(document).ready(function() { | |
var jqxhr = $.ajax({ | |
url: '/discover', | |
dataType: 'json' | |
}).done(buildSearch); | |
loadDefaultParams(); | |
$('#request-add-param').on('click', function() { | |
addParam('', '', '', null); | |
return false; | |
}); | |
$(document).on('click', '.request-param-remove', function(event) { | |
$(event.currentTarget).parents('tr').remove(); | |
return false; | |
}); | |
$('form').on('submit', function() { | |
var url = $('#request-url').val(); | |
if (!url) { | |
alert('Where is the URL???'); | |
return false; | |
} | |
serviceRequest(url); | |
return false; | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment