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: