Posted by Mark Hansen at 1:56 PM
Here is the envelope structure I use for my JSON messages.
{
"message_id":"message_id_000001",
"status":"[SUCCESS|ERROR|WARNING]",
"status_code":"[200|404|500|etc]",
"messages":[
{
"message_order":"1",
"message_type":"[ERROR|WARNING|INFO|DEBUG|TRACE]",
"message_format":"[HTML|TEXT]",
"message":"message text here"
},
{
"message_order":"2",
"message_type":"[ERROR|WARNING|INFO|DEBUG|TRACE]",
"message_format":"[HTML|TEXT]",
"message":"message text here"
}
],
"data":[
{
"data_1":"data 1"
},
{
"data_2":"data 2"
}
]
}
The structure is pretty verbose, it's almost like using SOAP XML calls...almost. The important point for me, is that I can easily debug the JS code my application is processing. I still have not figured out the security part though. Most of the time I actually forget (I'm getting old!) what the actual structure of my response is, so I just create a handy class based on a HashMap. Why a HashMap? Because I do not know what other data may be required for transmission to other clients. This way I can add them without having to upgrade everything else.
Here's the class I use:
package info.markhansen.json; import java.rmi.server.UID; import java.util.Collection; import java.util.HashMap; import java.util.TreeMap; public class JsonEnvelopeextends HashMap { public static final String STATUS = "status"; public static final String STATUS_CODE = "status_code"; public static final String DATA = "data"; public static final String MESSAGES = "messages"; public static final String MESSAGE_ID = "message_id"; public JsonEnvelope() { // Create a unique ID for this message this.put(MESSAGE_ID, new UID()); // Make sure the messages array is not null this.put(MESSAGES, new TreeMap ()); // Set the default status to success this.setStatusOther("SUCCESS"); // set the default status code to success this.setStatusCode(200); } public String getMessageId() { return (String)this.get(MESSAGE_ID); } public void setStatusSuccess() { this.setStatusOther("SUCCESS"); } public void setStatusError() { this.setStatusOther("ERROR"); } public void setStatusOther(String status) { this.put(STATUS, status); } public void setStatusCode(int statusCode) { this.put(STATUS_CODE, new Integer(statusCode)); } public void setData(Collection data) { this.put(DATA, data); } public void setMessages(TreeMap messages) { if (null != messages) { this.put(MESSAGES, messages); } } public void addMessage(String message) { final TreeMap messages = (TreeMap)this.get(MESSAGES); messages.put(new Integer(messages.size() + 1), message); } }
Posted by Mark Hansen at 1:57 PM
Usually when working on the interface for an application, there are multiple items which require an $.ajax call of some sort. Auto Complete fields, tables, drop downs, combo boxes, you get the idea. Now, before I learned about JQuery deferred objects, I would have an $.ajax call inside of my event handler methods. I know it's not the best way, but it's the most straightforward way I could implement it when I first began to use JQuery. The code ended up looking like the following:
cmdAddUser.click(function () {
var useridToAdd = $("#newUserIdToAdd").val();
var messageContainer = $("#messageContainer");
$.ajax({
type: "POST",
url: "/service/users/add",
dataType: "json",
data: {
userid: useridToAdd
},
success: function (data) {
var statusCode = data.response.status_code;
messageContainer.html('');
switch (statusCode) {
case "200":
messageContainer.addClass('ui-state-highlight');
messageContainer.html('<ul><li>' + data.response.status_message + '</li></ul>');
break;
default:
var messages = '<ul>';
$.each(data.response.errors, function (index, value) {
messages += '<li><pre>' + value + '</pre></li>';
});
messages += '</ul>';
messageContainer.html(messages);
break;
}
},
error: function (xhr, s, e) {
alert(s.error_status);
}
});
});That's a pretty ugly snippet of code.
However, with the Deferred Objects introduced in JQuery 1.5 I can clean up that code:
With the $.ajax call isolated, I can now use this call in multiple places through out the site without having to repeat the code. It's nice and DRY (Don't Repeat Yourself...Dum Dum) now.
function addUser(messagesContainer, newUserParameters) {
return $.post('/service/users/add', newUserParameters).error(function (xhr) {
var jsonData = $.parseJSON(xhr.responseText);
// this is a generic error reporting function
reportErrors(messagesContainer, jsonData.response.errors);
});
};
cmdAddUser.click(function () {
var useridToAdd = $("#newUserIdToAdd").val();
var messageContainer = $("#messageContainer");
var c = addUser(messageContainer, {
userid: useridToAdd
});
c.success(function (data) {
messageContainer.addClass('ui-state-highlight');
messageContainer.html('<ul><li>' + data.response.status_message + '</li></ul>');
});
});