The HTML example demonstrates the following:
- MySafeInfo's WICK API (RESTful)
- JavaScript
- jQuery (2.1.4)
- Bootstrap (3.3.5)
- Font Awesome (4.3.0)
- AJAX (asynchronous and synchronous)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Bucket List</title>
<style type="text/css">
body {
margin: 0px 25px !important;
}
td.icons {
font-size: 18px !important;
}
td.icons i {
cursor: pointer;
padding: 0 15px;
}
.icon-cancel.disabled {
color: #cccccc;
cursor: not-allowed;
}
</style>
<!-- jquery -->
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- bootstrap -->
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- font awesome -->
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<!-- custom script -->
<script type="text/javascript">
// variables
var readerKey = "28SFkEKyZucdjEvaqYGLD3SY2d9dsnqb";
var insertKey = "3InDNvlJnYzSGAHRjT2tUEB4MRygJtuV";
var updateKey = "iP3wwSUtuSLFoi4HNzmZIOazxckoldaN";
var deleteKey = "LqNQuiJ5Eg8FSzWBJZj2FLO0n0PDrM7L";
var table = "BucketList"
// format
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
$(function () {
// initialize
BindData();
// bind data
function BindData() {
// variables
var grid = $("#grid");
// ajax variables
var type = "GET";
var url = "https://mysafeinfo.com/wick/{0}/tables/{1}".format(readerKey, table);
var contentType = "application/json; charset=utf-8";
var dataType = "json";
var data = "";
var async = true;
// get the data from database table
$.ajax({
type: type,
url: url,
contentType: contentType,
dataType: dataType,
data: data,
async: async
}).done(function (result) {
// variables
var result = $(result);
var rows = "";
var columns = "";
// heading
$("h3.table-results").text("{0} record{1}".format(result.length, (result.length > 1 | result.length == 0) ? "s" : ""));
// get the template (schema) for this table
var template = GetTableTemplate();
// append a blank record so they can do an inline add in the grid
result.splice(0, 0, template);
// for each row
result.each(function (i, item) {
// variables
var key = "ID";
var id = item[key];
// clear columns
columns = "";
// begin new row
rows = "{0}<tr data-id='{1}'>".format(rows, id);
// get column list
for (var column in item) {
// variables
var value = item[column];
// get column headers
columns = "{0}<th>{1}</th>".format(columns, column);
// check to see if this is an existing record or the blank record for the inline add
// if an existing record show the data as-is
// if the blank record show NEW for the ID column and empty textboxes for the other fields
if (id > 0) {
rows = "{0}<td data-column='{2}' data-value='{1}'>{1}</td>".format(rows, value, column);
}
else {
if (column == key) {
rows = "{0}<td data-column='{2}' data-value='0'><i class='fa fa-plus-circle icon-new' alt='New' title='New'></i></td>".format(rows, value, column);
}
else {
rows = "{0}<td data-column='{2}' data-value='{1}'><input type='text' value='' maxlength='100' data-column='{2}'/></td>".format(rows, value, column);
}
}
}
// check to see if this is an existing record or the blank record for the inline add
// if an existing record show the edit and delete icons
// if the blank record show the save and cancel icons
if (id > 0) {
rows = "{0}<td class='icons text-right'><i class='fa fa-pencil icon-edit' alt='Edit' title='Edit'></i><i class='fa fa-trash-o icon-delete' alt='Delete' title='Delete'></i><i class='fa fa-save icon-save hidden' title='Save' alt='Save'></i><i class='fa fa-times icon-cancel hidden' title='Cancel' alt='Cancel'></i></td></tr>".format(rows);
}
else {
rows = "{0}<td class='icons text-right'><i class='fa fa-plus icon-save' title='Save' alt='Save'></i><i class='fa fa-times icon-cancel disabled' title='Cancel' alt='Cancel'></i></td></tr>".format(rows);
}
});
// columns
columns = "{0}<th></th>".format(columns);
// table
var table = "<table id='table-data' class='table table-striped table-responsive table-hover results'><thead><tr>{0}</tr></thead><tbody>{1}</tbody></table>".format(columns, rows);
// add data to grid
grid.html(table);
}).always(function () {
});
}
// edit
$("body").delegate("table.results tbody tr td i.icon-edit", "click", function () {
// variables
var td = $(this).parent("td");
var tr = $(td).parent("tr");
// toggle icons
$(td).children("i.icon-edit").addClass("hidden");
$(td).children("i.icon-delete").addClass("hidden");
$(td).children("i.icon-save").removeClass("hidden");
$(td).children("i.icon-cancel").removeClass("hidden");
// add input fields to each cell
for (var i = 1; i < tr.children("td").length - 1; i++) {
// variables
var cell = tr.children("td")[i];
// add input to cell
$(cell).html("<input type='text' value='{1}' maxlength='100' data-column='{0}'/>".format($(cell).data("column"), $(cell).text().trim()));
// set focus to the first input
if (i == 1) { $(cell).children("input").focus(); }
};
// keydown event to capture enter key
$(window).keydown(function (event) {
if (event.which == 13) {
event.preventDefault();
td.children("i.icon-save").trigger("click");
}
});
});
// delete
$("body").delegate("table.results tbody tr td i.icon-delete", "click", function () {
if (confirm("Are you sure you want to delete this record?")) {
// variables
var tr = $(this).parent("td").parent("tr");
var id = $(tr).children("td").first().text();
// ajax variables
var type = "DELETE";
var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/{2}".format(deleteKey, table, id);
var contentType = "application/json; charset=utf-8";
var dataType = "json";
var data = "";
var async = false;
// delete
$.ajax({
type: type,
url: url,
contentType: contentType,
dataType: dataType,
data: data,
async: async
}).done(function (result) {
// bind data
BindData();
// show message
alert(result.Message);
}).always(function () {
});
}
});
// save
$("body").delegate("table.results tbody tr td i.icon-save", "click", function () {
// variables
var tr = $(this).parent("td").parent("tr")
var id = tr.data("id");
var request = "";
var isValid = false;
// create request
for (var i = 1; i < tr.children("td:not(.icons)").length; i++) {
// controls
var input = $(tr.children("td")[i]).children("input");
// variables
var column = $(input).data("column");
var value = $(input).val().trim();
// append to request
request = '{0} "{1}":"{2}",'.format(request, column, value)
// is valid flag if at least one field has data
if (value.length > 0) {
isValid = true;
}
}
// make sure at least one field has data, otherwise nothing to add/update
if (!isValid) {
alert("Please enter a value for at least one field.");
tr.children("td").find("input").first().focus();
tr.children("td").find("input").first().select();
return;
}
// format json request
request = "{{0}}".format(request.substring(1, request.length - 1));
// check to see if we need to do an insert or an update
if (id > 0) {
// ajax variables
var type = "PUT";
var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/{2}".format(updateKey, table, id);
var contentType = "application/json; charset=utf-8";
var dataType = "json";
var data = request;
var async = false;
// update
$.ajax({
type: type,
url: url,
contentType: contentType,
dataType: dataType,
data: data,
async: async
}).done(function (result) {
// bind
BindData();
// message
alert(result.Message);
}).always(function () {
// remove key event listener
RemoveListener();
});
}
else {
// ajax variables
var type = "POST";
var url = "https://mysafeinfo.com/wick/{0}/tables/{1}".format(insertKey, table);
var contentType = "application/json; charset=utf-8";
var dataType = "json";
var data = request;
var async = false;
// insert
$.ajax({
type: type,
url: url,
contentType: contentType,
dataType: dataType,
data: data,
async: async
}).done(function (result) {
// bind
BindData();
// message
alert(result.Message);
}).always(function () {
// remove key event listener
RemoveListener();
});
}
});
// cancel
$("body").delegate("table.results tbody tr td i.icon-cancel", "click", function () {
// variables
var tr = $(this).parent("td").parent("tr")
var id = tr.data("id");
// short-circuit if this is a new record
if (id < 1) {
return;
}
// set defaults
for (var i = 1; i < tr.children("td:not(.icons)").length; i++) {
var td = $(tr.children("td")[i]);
td.text(td.data("value"));
}
// toggle icons
$(this).parent("td").children("i.icon-edit").removeClass("hidden");
$(this).parent("td").children("i.icon-delete").removeClass("hidden");
$(this).parent("td").children("i.icon-save").addClass("hidden");
$(this).parent("td").children("i.icon-cancel").addClass("hidden");
// remove key event listener
RemoveListener();
});
function GetTableTemplate() {
// variables
var template;
// ajax variables
var type = "GET";
var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/template".format(readerKey, table);
var contentType = "application/json; charset=utf-8";
var dataType = "json";
var data = "";
var async = false;
// get table template
$.ajax({
type: type,
url: url,
contentType: contentType,
dataType: dataType,
data: data,
async: async
}).done(function (result) {
template = result;
}).always(function () {
});
// return
return template;
}
function RemoveListener() {
$(window).unbind("keydown");
}
});
</script>
</head>
<body>
<!-- container for header to indicate how many records were retrieved -->
<h3 class="table-results">0 records</h3>
<!-- container for html table built dynamically from our ajax call -->
<div class="table-responsive">
<div id="grid"></div>
</div>
</body>
</html>
I've also included examples using .Net 4.5 (C# and VB.Net) for those looking to call a RESTful API from the server-side, which can be helpful when working with key-based APIs, so you can hide your API keys. The .Net 4.5 examples demonstrate the following:
- MySafeInfo's WICK API (RESTful)
- Json.NET (Newtonsoft.Json)
- WebClient.UploadString
using System;
using System.Net;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
// variables
string Table = "BucketList";
string InsertKey = "3InDNvlJnYzSGAHRjT2tUEB4MRygJtuV";
string DeleteKey = "LqNQuiJ5Eg8FSzWBJZj2FLO0n0PDrM7L";
string InsertUrl = string.Format("https://mysafeinfo.com/wick/{0}/tables/{1}", InsertKey, Table);
PostResult PostResult = new PostResult();
WickResult WickResult = new WickResult();
BucketList BucketList = new BucketList { Description = "Run a mini-marathon", Notes = "2016 OneAmerica 500 Festival Mini-Marathon", Date = "May 2016" };
// use Json.NET (Newtonsoft.Json) to serialize the data object
// https://www.nuget.org/packages/Newtonsoft.Json
string Data = JsonConvert.SerializeObject(BucketList);
// post the data to the MySafeInfo WICK API
PostResult = SubmitRequest(Url: InsertUrl, Data: Data);
// use Json.NET (Newtonsoft.Json) to deserialize json result into a strongly typed data object
// https://www.nuget.org/packages/Newtonsoft.Json
if (PostResult.Success)
{
WickResult = JsonConvert.DeserializeObject<WickResult>(PostResult.Message);
}
// debug
Console.WriteLine(string.Format("WICK Input: {0}", Data));
Console.WriteLine(string.Format("WICK Output: {0}", PostResult.Message));
Console.WriteLine(string.Format("ID: {0}", WickResult.ID));
Console.WriteLine(string.Format("Success: {0}", WickResult.Success));
Console.WriteLine(string.Format("Message: {0}", WickResult.Message));
// just for fun we are going to delete the record to show how simple a delete is
if (WickResult.Success)
{
Console.WriteLine(string.Format("Delete: {0}", SubmitRequest(Url: string.Format("https://mysafeinfo.com/wick/{0}/tables/{1}/{2}", DeleteKey, Table, WickResult.ID), Method: "DELETE").Message));
}
}
public static PostResult SubmitRequest(string Url, string Data = "", string Method = "POST", string ContentType = "application/json; charset=utf-8")
{
// variables
PostResult Result = new PostResult();
try
{
// web client
using (WebClient Client = new WebClient())
{
// content type
Client.Headers[HttpRequestHeader.ContentType] = ContentType;
// post data and get result
Result.Message = Client.UploadString(address: Url, method: Method, data: Data);
Result.Success = true;
}
}
catch (Exception ex)
{
Result.Message = ex.Message;
}
// return
return Result;
}
// helper classes
public class BucketList
{
public string Description { get; set; }
public string Notes { get; set; }
public string Date { get; set; }
}
public class PostResult
{
public bool Success { get; set; }
public string Message { get; set; }
}
public class WickResult
{
public int ID { get; set; }
public bool Success { get; set; }
public string Message { get; set; }
}
}
As you can see, the server side code is relatively simple since we can leverage Json.NET to serialize and deserialize our data, and we can use built in .Net namespaces (WebClient) to perform our RESTful operations against the API.
Here are links to each example:
- Bucket List Demo (HTML, JavaScript, jQuery)
- Bucket List Demo (.Net 4.5, C#)
- Bucket List Demo (.Net 4.5, VB.Net)
Whether you are using client-side scripting or server side scripting, you can see that using JSON data with a RESTful API can be very easy to implement.

0 comments: