1024px-Flatirons_Winter_Sunrise_edit_2

This is post 3 in a series on creating a JavaScript component for handling your Ajax requests in front-end development across your enterprise. You can find all the other posts here:

In the last post we covered using the publish/subscribe pattern along with some error handling code to add some loosely coupled error messaging and load notifications. We ended with the following code for the component:

[js] var mySiteAjax = ( function( $ ) {
var standardError = “Oops. Sorry about that. Please try again.”;

return {
getViaAjax: function( params ) {
var settings = $.extend({
url: ”,
spinner: undefined,
dataType: ‘html’,
cache: false,
success: function(){}
}, params);

var retries = 0;
function ajaxRequest ( ) {
$.ajax({
beforeSend: function(){
$(document).trigger( “ui-load-start.message”,
[{ spinner: settings.spinner }] );
},
url: settings.url,
dataType: settings.dataType,
success: settings.success,
complete: function(){
$(document).trigger( “ui-load-end.message”,
[{ spinner: settings.spinner }] );
},
error: function( xhr, tStatus, err ) {
if( xhr.Status === “401” || xhr.Status === “403” ) {
//redirect action here
} else if ( xhr.Status === “504” && !retries++ ) {
ajaxRequest();
}
$(document).trigger( “ui-flash.message”,
[{ message: standardError }] );
} // end error handler
}); // end $.ajax()
}; // end ajaxRequest()
ajaxRequest();
} // end getViaAjax()
}; // end return statement
})(jQuery);
[/js]

In this post we are going to take this code and add on some explicit functionality for handling a JSON envelope.

## What is a JSON Envelope
A JSON envelope is a wrapper around JSON returning from the server. The wrapper serves to communicate any failures or messages back to the client along with the appropriate data if the request succeeded.

Consider a scenario where you are sending the server a few parameters and hope to receive a JSON structure back. What happens if you were to send a parameter which was invalid? The server would not be able to respond with the appropriate data and a failure should be communicated.

This is different from an HTTP status code as we were able to communicate with the server successfully. We need a solution to communicate any issues which may have occurred in the server code providing a successful response to our request.

A JSON envelope is a simple mechanism to communicate messages and failures to the client as part of a JSON response. Typically the intended data for the client is wrapped in an object. The JSON object sent back to the client includes this wrapped data if successful. If not the object sent back includes a message. In all cases the response object contains a status indicator.

A typical successful JSON enveloped response might look like this:

[js] {
“status”: “ok”,
“data”: {
“myData”: “someData”
}
}
[/js]

An error response contains a status property as well as a message property indicating the issue:

[js] {
“status”: “fail”,
“message”: “You did not supply the correct input data.”
}
[/js]

Another advantage of using a JSON envelope is that the object wrapper will alleviate a subtle JSON vulnerability (outlined [here](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) by Phil Haack).

### JSON Envelopes in use today

Many public services are implementing JSON envelopes for simple messages and error communication. The [Flickr API](http://www.flickr.com/services/api/) has a JSON envelope in place for simple communication of failures. You can find more information on the [JSON response format](http://www.flickr.com/services/api/response.json.html) page as well as example of [success](http://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api_key=560f2f65e11cef441ba757d2b509b157) and [failure](http://www.flickr.com/services/rest/?method=flickr.blogs.getList&format=json&api_key=560f2f65e11cef441ba757d2b509b157) responses.

## Handling a JSON Envelope

Our first step is to handle the JSON envelope in our Ajax utility component and take action if a failure occurred. If the envelope indicates a successful response we need to invoke the success callback. As a reminder from last post settings.success is the success callback provider by the calling code (or an empty function if none was provided):

[js] var mySiteAjax = ( function( $ ) {
//..
$.ajax({
//…
success: function(wrapper, tStatus, xhr) {
if(!settings.type.match(/^json/i)) {
return settings.success.call( this, wrapper,
tStatus, xhr);
if(wrapper.status === “success”) {
return settings.success.call( this, wrapper.data,
tStatus, xhr);
}
$(document).trigger( “ui-flash.message”,
[{message: wrapper.message}] );
},
//…
});
//…
})(jQuery);
[/js]

We have created a success function callback that will be run when the response returns from the server. We will inspect the envelope for a status and will take action if the status is not successful. If it is a success, we will call the success callback provided in our settings.

The code snippet return settings.success.call( this, wrapper, tStatus, xhr); is particularly interesting. This may be the first time you have seen the functionName.call() method in JavaScript. This method allows us to set the context of the this argument in the function call. We could have done the following:

[js] //…
if(wrapper.status === “success”) {
setting.success(wrapper.data, tStatus, xhr);
}
//…
[/js]

But what is the context of this in that case? Probably not what the settings.success callback would expect. If instead we use the functionName.call() JavaScript function we can set the context of this as well as all the other arguments for the function call. This allows us to precisely supply the context expected by the settings.success function.

To handle the error message we added the following action:

[js] //…
$(document).trigger( “ui-flash.message”,
[{message: wrapper.message}] );
//…
[/js]

We are “publishing” by using jQuery events with a custom event name. Our “message topic” indicates that there is information that should be shared with the user. It is up to another component on our page to have subscribed to this topic and to take the appropriate action. We do not have to care if the message is actually published to the user, or how it is done. We have achieved separation of concerns. Doesn’t it feel nice?

## Handling different JSON Envelopes
Different JSON envelope implementations mean different JavaScript properties and success/failure statuses to deal with. Some sites may not have a JSON envelope. Our utility component needs to handle all these cases.

To do this we will add global settings. This will allow the user to set global defaults while using arguments specified to mySiteAjax() if a specific call involves a different JSON envelope.

To handle global setting we will add a settings property onto our mySiteAjax object. The code snippet below is long, but bear with me. We will break it down below.

[js] var mySiteAjax = ( function( $ ) {
var standardError = “Oops. Sorry about that. Please try again.”;

// create new Ajax utility as a “private” variable
var myAjax = function( params ) {

// add together global settings with arguments
var params = $.extend({},
myAjax.settings, params);

var retries = 0;

function ajaxRequest ( ) {

$.ajax({
// publish “local” loading start message
beforeSend: function(){
$(document).trigger( “ui-load-start.message”,
[{ spinner: params.spinner }] );
},
type: params.type,
url: params.url,
data: params.data,
dataType: params.dataType,
success: function(wrapper, tStatus, xhr) {

// if json is the data type and the json wrapper exists
if( (/^json/i).test(params.dataType)
&& params.env.hasEnv) {
if(wrapper[params.env.statName] === params.env.successInd) {

// since wrapper indicated a success,
// call original success callback with the
// unwrapped JSON contents
return params.success.call( this,
wrapper[params.env.dataName],
tStatus, xhr);
}

// success wasn’t indicated, publish
// message
$(document).trigger( “ui-flash.message”,
[{message: wrapper[params.env.msgName]} ] );
} else {

// return unwrapped if response wasn’t json or no envelope
// was specified
return params.success.call( this, wrapper,
tStatus, xhr);
}

},

// publish “local” loading end message
complete: function(){
$(document).trigger( “ui-load-end.message”,
[{ spinner: params.spinner }] );
},
error: function( xhr, tStatus, err ) {
if( xhr.Status === “401” || xhr.Status === “403” ) {
//redirect action here
} else if ( xhr.Status === “504” && !retries++ ) {
ajaxRequest();
}
$(document).trigger( “ui-flash.message”,
[{ message: standardError }] );
} // end error handler
}); // end $.ajax()
}; // end ajaxRequest()
ajaxRequest();
};

// settings which are global and attached
// to the myAjax function as a property
myAjax.settings = {
url: “”,
spinner: undefined,
dataType: “json”,
cache: false,
type: “GET”,
success: function(){},
env: {
hasEnv: true,
statName: “status”,
successInd: “success”,
dataName: “data”,
msgName: “message”
}
};

//returns the newly created function with the properties attached.
return myAjax;

})(jQuery);
[/js]

You’ll notice we moved around things. The function is now specified as a named function (although the scope is still within our component code only). We’ve also moved our settings to a property of our main utility function. Since JavaScript functions are objects augmenting it with properties is valid. You’ll also notice that we have an empty object literal as the first parameter to $.extend(). This is because the extend method will merge all of the object together and replace the first object with the merged results. We do not want to overwrite our global setting object each time!

Exposing our settings as a property gives us a clean way to specify defaults for a specific page. For example we can set the default HTTP action to POST with minimal effort:

[js] myAjax.setting.type = “POST”;
[/js]

We’ve added settings for the JavaScript envelope. With our settings we can determine whether or not an envelope is used and how to leverage the envelope. Turning off the envelope functionality is now a one line setting:

[js] myAjax.setting.env.hasEnv = false;
[/js]

In our wrapper code we have changed the way we access objects. For example there is now this snippet:

[js] //…
if( wrapper[params.env.statName] === params.env.successInd ) {
//…
[/js]

Remember that we can access object properties through dot notation or bracket notation. Bracket notation allows you to specify the name of the property as a string. In our above example, with our default global setting of “success” as our status name, the code would evaluate to wrapper["success"]. This would access the success property of the wrapper object. So using this piece of functionality we do not even need to know the names of the properties of our JSON object until runtime!

We now have a working Ajax Utility Component which includes a JSON envelope! I’ve set up a few examples and a playground for the component as a [jsFiddle](http://jsfiddle.net/YLKUz/1/). Please play around and ask questions in the comments!