JSON and JSONP in jQuery - Back to Basics

Datetime:2016-08-22 23:48:36          Topic: jQuery  JSONP           Share

Now-a-days, it’s fairly common to request data in JSON format. It’s lighter-weight than XML, very easy to work as Ajax responses, when dealing with complex data and has generally speaking, become the most popular way of transferring data.

If you are new to Ajax as well as jQuery’s implementation of Ajax and JSON/JSONP, read Getting started with jQuery $.ajax() – Back to Basics before you proceed further.

Using jQuery to get JSON data from the server is extremely easy. In this article, we will see a simple example of consuming data from a local URL and remote URL that returns data in JSON format. For our first example, we will take a JSON containing country names and populate a DropDown/HTML Select box with the values.

Create a new file called ‘SimpleJSON.html’. Here’s a snapshot of the JSON that we will be consuming. Save this file as countries.json:

{
	"countries": {
		"country": [
			{
				"id": 1,
				"cname": "Japan",
				"capital": "Tokyo"
			},
			{
				"id": 2,
				"cname": "India",
				"capital": "Delhi"
			},
			...
		]
	}
}

The barebones syntax of using $.ajax() to consume this JSON is as follows.

<script>
	$(function () {
		$.ajax({
			"url": "/scripts/S9/countries.json",
			"type": "get",
			"dataType": "json"
		})
		.done(function (data) {
		})
		.fail(function(jqXHR, status, error) {
		})
	});
</script>

We will implement the code that goes into done() and fail() in a bit.

In the example above, we are passing in an object of arguments/options to $.ajax(). The first argument is a local URL - "scripts/countries.json”. The next argument is the type of request to make, in our case GET, since we are only planning to read the data. The third argument is dataType which represents the type of data returned to you.

The jqXHR object returned by $.ajax() implements the Promise interface (as of jQuery 1.5 and above). So here we are using the Promise methods done() and fail() of the jqXHR object.

  • jqXHR.done(function( data, textStatus, jqXHR ) {})
  • jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {});
  • jqXHR.always(function( data|jqXHR, textStatus, jqXHR|errorThrown ) { });

where data is the response from the server, in our case JSON.

textStatus is a string denoting the status like “success” "notmodified", "error", "timeout", "abort", or "parsererror" and

jqXHR returns the jqXHR object.

If you are still using the jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks, then please note that these have been deprecated in jQuery 1.8. Use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

With the basic structure defined, let’s implement the code in the .done() and .fail() method.

.done(function (data) {
	var options = $("#country");
	$.each(data.countries.country, function (idx, val) {
		options.append($('<option />', { value: idx, text: val.cname }));
	});
})
.fail(function(jqXHR, status, error) {
	console.log("status:", status, "error:", error);
})

Here I am caching $(“#country”) outside the loop for a slight performance benefit. I then use $.each to loop over each country and execute a function for each element. The function takes two parameters. The first is the index of the item and the second is the item itself. We finally do options.append to add each country name to a DropDown list.

As of jQuery 1.9, an empty response is rejected. Your server should return a response of null or {} instead.

Using $.getJSON shorthand method

jQuery provides a shorthand method for fetching JSON data: $.getJSON. It’s called a shorthand method as behind the scenes it calls $.ajax() and has a shorter syntax. The basic version of this method accepts a URL to the JSON file and a success parameter that consists of a callback function that will be called if the request is successful.

Here’s the same code using $.getJSON

$(function () {
	$.getJSON('/scripts/S9/countries.json',
	function (result) {
		var options = $("#country");
		$.each(result.countries.country, function (idx, val) {
			options.append($('<option />', { value: idx, text: val.cname }));
		});
	});
});

If you observe there’s no error callback defined. This is because getJSON supports a callback function only for requests that have succeeded. In real applications, errors occur and it’s a good habit to handle these errors. For this reason, I recommend to use the $.ajax() method and not the shorthand method that we just saw. I have used the shorthand method in this article for educational purposes.

There is no equivalent $.postJSON() method.

Live Demo : http://www.jquerycookbook.com/demos/S7-Ajax/53-SimpleJSON.html

A Simple JSONP Example

On many occasions, you may come across a requirement to request data from a remote website. These websites provide APIs that accept requests and send back a response. For security reasons, Ajax requests are limited to the same domain or also known as the same origin . In this context, an origin is the combination of three components: URL protocol, hostname and port. If two URLs have the same components, then they are within the same origin , however if any of the components is different, then they are of different origins or cross origin .

For eg: http://www.jquerycookbook.com and https://www.jquerycookbook.com are of different origins as the protocol differs - http and https.

This cross domain policy is enforced to reduce the risks of a cross-site scripting (CSS) attack, where the browser or user maliciously attempts to contact another site.

So how do you make Ajax requests outside your domain or in other words, how do you make cross-domain Ajax requests? jQuery makes it possible to request JSON data outside the domain by requesting JSON with Padding – also known as JSONP . In your Ajax request, if the data is marked as JSONP, jQuery appends a query string parameter callback=? to the URL. Alternatively, you can also manually add &jsoncallback=? to the URL which notifies the calling site that you want to receive JSONP data. Doing so also lets jQuery’s $.getJSON() function treat this request as if the browser was requesting an external JavaScript file. Simply put, JSONP is JSON wrapped inside a function call

Let’s see this in action. We will use the Ziptastic API service ( http://ziptasticapi.com/ ) which accepts a US zip code and returns City and State based on it and gives the data back in JSONP format which you can consume in your jQuery application.

The format of the API call is : http://ziptasticapi.com/zipcode?callback=mycallback

An important thing to observe in this API url is that ZipCode is part of the url.

Create a file ‘SimpleJSONP.html’. Let’s declare two text boxes, one for the Zip code and the other for the City.

<body>
    <label for="zip">ZIP:</label>
    <input type="text" name="zip" id="zip"/>

    <label for="city">City:</label>
    <input type="text" name="city" id="city" />
</body>

Here’s the code to consume this API:

<script type="text/javascript">
	$(function () {
		$("#zip").on('change', function () {
			var zip = $(this).val();
			var url = "http://ziptasticapi.com/" + zip + "?callback=?";
			$.getJSON(url, null, function (result) {				   
				if (result.city)
					$("#city").val(result.city);
			});
		});
	});
</script>

We start by monitoring the change event on the Zip Code textbox. We then use val() to retrieve the value of the Zip Code entered by the user in a variable zip. Since the Ziptastic API is of the format http://ziptasticapi.com/zipcode?callback=mycallback , in our code, we are concatenating the zip code in the url, followed by the callback parameter to tell the API to return JSONP.

We then use $.getJSON and pass in the url and a success parameter result that consists of a callback function that will be called if the request is successful. Inside the callback function, we check the value of the city and if it exists, update the value of the City textbox.

Run the example, enter a zip code say 94101 and hit tab. You will see that the City textbox populates with the City name

Live Demo : http://www.jquerycookbook.com/demos/S7-Ajax/54-SimpleJSONP.html

Can cross-domain Ajax Requests work without specifying the callback parameter?

With some websites, you may observe that cross-domain Ajax request works even when you are not using JSONP explicitly. So how’s that possible? In such cases, always check the HTTP Response Header returned by the server. If the server responds with an Access-Control-Allow-Origin: * it means that the resource can be accessed by any domain in a cross-site manner.

Let’s try this with the ziptastic service by removing the callback from the url.

var url = "http://ziptasticapi.com/" + zip;

As you can see, we are not specifying the callback in this url string. Run the example and you will see that the output remains the same. In the Google Chrome Developer Tools (Ctrl + Shift + I), if you see the HTTP Response Header returned by Ziptastic, you will observe that it responds with an Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner.

So make sure you keep this point in mind while making JSONP calls. I generally use the callback parameter when and where I can.

JSONP is actually a hack and thus contains security risks. A lack of proper error handling mechanism also makes it tough to debug, when calls don’t work as expected.

Take a look at my new book The Absolutely Awesome jQuery Cookbook which contains scores of practical jQuery/jQueryUI recipes you can use in your projects right away.





About List