• Posted on May 8, 2013

How JSON P Works With Library

Having a dynamic website is now the norm when it comes to website design and development. People want the most up to date content, posts, images, and everything else right away without having to refresh their web browser. The method most websites use to provide dynamic content is called AJAX or known as XMLHttpRequest or XHR for short.

XHR has a few limitations though, such as not being able to get content from other domains easily. So if you do want to have dynamic content it has to be from the same domain you have your website on. This is of course a problem when you want to use an external API such as Twitter, Facebook, Twitch, YouTube and others. But there is another client side solution called JSON P. In the steps below I will show you how to create a library to use JSON P and how exactly JSON P works.

How JSON P Works

The magic behind JSON P is loading scripts dynamically. Since web browsers allow scripts, stylesheets, and images to be loaded from external sources we use this to our advantage. We create a new script element with the API URL we want to call. With the loaded script, the API’s server wraps the JSON data with a call to a function we specify in a url parameter. Most of the time this parameter will be “callback” but I’ve seen it be almost anything. What this does is, runs the function we specified that we have already created, and all the data is passed to the first argument of the function for us to work with. It is the same as if we loaded another javascript file calling to a function with data as the first parameter, but with JSON P it is from an external source.

  1. This step is just the loading of the JSON P library we are going to be using (below). The website or webpage basically loads the script to be used in the near future.
  2. After the website calls the function jsonP(); - the JSON P script creates a new “script” element with the URL we request. After this step we wait for a response or error.
  3. The Requested API URL returns. The data is returned as a function call with all the data in the first argument for the function. The library creates a dynamic function to keep async calls working properly.
  4. After our JSON P library figures out if the call was successful or not we run the Success or Error functions. If we receive a response we will run the success. Error is only ran if there is a timeout aka error.

Creating JSON P JavaScript Library

/*
	Copyright 2013 Geek This
	http://www.geekthis.net
	Use of this code is free and provided As-Is with no warranty.
	Updated: May 7, 2013 at 11:09am
*/
var jsonP_Global = new Object();
var jsonP_Callback = function(data) {
	if(this.error == true) {
		delete jsonP_Global[this.uniqueID];
		return;
	}
	clearTimeout(this.timerError);
	document.body.removeChild(this.script);
	if(typeof this.callbackSuccess == "function") {
		this.callbackSuccess(data);
	}
	delete jsonP_Global[this.uniqueID];
};
var jsonP = function(url,args) {
	var obj = new Object();
	obj.timeout = 5000;
	obj.callbackSuccess = null;
	obj.callbackError = null;
	obj.callbackParam = "callback";
	obj.error = false;
	obj.script = document.createElement('script');
	obj.uniqueID = 'c' + Math.random().toString(36).substr(2,9);
	obj.callback = jsonP_Callback;
	if(args) {
		if(args.timeout)
			obj.timeout = args.timeout;
		if(args.success)
			obj.callbackSuccess = args.success;
		if(args.error)
			obj.callbackError = args.error;
		if(args.callback)
			obj.callbackParam = args.callback;
	}
	obj.timerError = setTimeout(
		function() {
			jsonP_Global[obj.uniqueID].error = true;
			document.body.removeChild(obj.script);
			if(typeof obj.callbackError == "function") {
				obj.callbackError();
			}
		},obj.timeout
	);
	obj.script.setAttribute('id', obj.uniqueID);
	if(url.indexOf('?') == -1) {
		obj.script.setAttribute('src',url + '?' + obj.callbackParam + '=jsonP_Global.' + obj.uniqueID + '.callback');
	}else{
		obj.script.setAttribute('src',url + '&' + obj.callbackParam + '=jsonP_Global.' + obj.uniqueID + '.callback');
	}
	jsonP_Global[obj.uniqueID] = obj;
	document.body.appendChild(obj.script);
};

The above code will be saved as a .js file and included into your webpage. You can include this either in the tags or somewhere in the body. But make sure your calls to the function happen after you include the above script.

To load a JSON P page using the above library you will create a JavaScript call similar to the below.

jsonP('http://api.sample.tld/users?limit=100',{
	callback:'jsonp',
	success:function(data){console.log(data);},
	error:function(){console.log('Error');},
	timeout:5000
});

The first parameter is the URL to the API call. Make sure the URL doesn’t have the callback parameter since the script has to generate a custom callback to track errors. The second parameter is an object where you can set the following.

callback: The name of the callback parameter in the URL. In the above case it uses “jsonp”. This is the parameter name you would normally set to the function you wish to call.

success: A function to run if the JSON P file load successfully. This is the “callback” that you want to run. It has to be a function and not a string to a function. Above we create an anonymous function. The success function gets a parameter passed to it with all the data returned from the JSON P request (the data).

error: The function to run if the JSON P file doesn’t load. Since tracking errors with JSON P is very difficult we use a timeout method. The reason for this is even if the file is 404 or 500 it will be marked as an error unlike other methods out there.

timeout: The time in milliseconds to wait before it is an error. The default value for this is 5000 or 5 seconds. You could increase or decrease this depending on your audience. But keep in mind if you set it too low a lot of users may be getting the error function.

The above code runs async so you can call as many JSON P objects as you want at the same time and they will all be handled properly and at the same time. The script also cleans up finished scripts and objects to keep the DOM and memory low.