What Is JSONP?
What Is JSONP?
Essentially, JSONP is a workaround to a problem we will look at throughout this section. It involves a clever technique that web developers started using to get around what is known as the same-origin policy ( http://en.wikipedia.org/wiki/Same_origin_policy), which is enforced in web browsers. With the same-origin policy in place, JavaScript code running in a browser is prevented from making an XMLHttpRequest ( http://en.wikipedia.org/wiki/XMLHttpRequest) to a URL that is different from the domain the script is running from. Therefore, if you attempt to access an application’s API from a client-side script running on a separate domain, the browser will step in and prevent it from happening.
To illustrate the problem, we will work through a small example. For example, consider the following code, which accesses the public Twitter API (see http://dev.twitter.com for more information) and displays the tweets on the page.
<html> <script src="../../js/jquery-1.4.2.min.js"></script> <script> function showData(data) {
var tweetItems = '';
if (! data) { tweetItems = '<li><strong>Could not retrieve tweets.</strong></li>'; } else {
for (var ii = 0; ii < data.length; ii++) {
tweetItems += '<li>' + data[ii].text + '</li>'; } // for }
$('#tweets').html(tweetItems); } // showData
$(document).ready(function() {
// make the request to the geonames server $.ajax({
url: 'http://api.twitter.com/1/statuses/public_timeline.json', dataType: 'json', success: showData
}); </script> <body>
<ul id="tweets"> </ul>
</body> </html>
The sample itself is simple enough—we make a request to the endpoint for the Twitter public timeline and then parse the response, filling the #tweets element with the tweets retrieved.
CHAPTER 10: Integrating with Social APIs
Let’s run that now. So that you can easily look at what’s going on in the background, we recommend working through this sample in your desktop browser. (We will be using Chrome.) Figure 10–1 shows the output generated from attempting to access the Twitter API using JSON from our local web server.
Figure 10–1. Attempting to access the Twitter JSON API from our local web server yields no results. Unfortunately, Figure 10–1 really doesn’t give us much idea as to what is going on—
except for the fact that our error-handling code is working correctly. So it’s time to dig in
a little. For this sample, we will be using the WebKit Inspector (see Appendix A for more details on debugging tools) to have a look behind the scenes. If you are using Chrome,
similar tools, so feel free to use your preferred toolset here. Figure 10–2 shows the network view from the Chrome developer tools.
CHAPTER 10: Integrating with Social APIs
Figure 10–2. The network view of the Chrome developer tools shows us where the problem exists. The network view in the developer tools confirms that the browser has indeed blocked
the cross-domain request in accordance with the same-origin policy. This is where a JSONP workaround comes into play. JSONP works within the bounds of
the same-origin policy, using rules that permit script includes from other domains. So, whereas a standard JSON request occurs via the XMLHttpRequest mechanism, a JSONP request is inserted and run as a script tag. This may sound a little confusing and take some time to get your head around if you haven’t come across JSONP before.
Well, let’s update our Twitter sample to use JSONP and see if we can gain an understanding of what’s going on.
<html> <script src="../../js/jquery-1.4.2.min.js"></script> <script> function showData(data) {
var tweetItems = '';
if (! data) { tweetItems = '<li><strong>Count not retrieve tweets.</strong></li>'; } else {
for (var ii = 0; ii < data.length; ii++) {
tweetItems += '<li>' + data[ii].text + '</li>'; } // for
CHAPTER 10: Integrating with Social APIs
$('#tweets').html(tweetItems); } // showData
$(document).ready(function() { // make the request to the geonames server $.ajax({
url: 'http://api.twitter.com/1/statuses/public_timeline.json', dataType: 'jsonp', success: showData
}); }); </script> <body>
<ul id="tweets"> </ul>
</body> </html>
The preceding code shows the modification required to have our test application communicate via JSONP rather than JSON. You can see here that jQuery does an excellent job of abstracting the complexity of JSONP away from us behind its $.ajax function. Figure 10–3 shows an example of the output generated by the modified sample.
Figure 10–3. Using JSONP, we can now retrieve the tweets of the world via the Twitter public timeline.
CHAPTER 10: Integrating with Social APIs
Now that we have looked at how simple it is to have jQuery issue a JSONP request for us, let’s take a quick look at what is going on behind the scenes. To achieve this, we will make a copy of our twitter-test.html file and replace the previous showData function with the following code:
function showData(data) { var tweetItems = '';
for (var ii = 0; ii < document.scripts.length; ii++) { var script = document.scripts[ii];
if (script.src) {
tweetItems += '<li>' + script.src + '</li>'; } // if } // for
$('#tweets').html(tweetItems); } // showData
So, rather than outputting the text of the tweets to the HTML, we are now writing out the source file location of any scripts that are currently included in the page. Figure 10–4 shows an example of what is displayed.
Figure 10–4 . Scripts that have been included in an HTML page reveal something of the nature of JSONP.
CHAPTER 10: Integrating with Social APIs
Ah, there we go—our call to Twitter has been included as a separate script in our page, but this doesn’t explain how we get the data back into our application. For that, we need to dig a little further. Figure 10–5 shows an example of the output that Twitter is generating when we call the script shown on this page.
Figure 10–5. Example output of the Twitter API when called using JSONP Things are starting to make sense now—the included script passes data back through a
function call. However, this is not a function that we have defined, but rather a function that has been created by jQuery with the specific purpose of receiving the data from the JSONP call. Once the jQuery function has received the data, it simply passes that information along to the callback that we provided when we made our $.ajax call.
NOTE: In general, you are probably better off using a JavaScript library such as jQuery to handle your JSONP calls, given the steps that are involved in getting it working. While we have covered some of what goes on behind the scenes here, it is far from an exhaustive list of the work that needs to be done. For further information, the following blog post provides a lightweight script that shows how JSONP works, and also provides an alternative to some of the more heavyweight implementations in jQuery and the like: www.nonobtrusive.com/2010/05/20/lightweight-jsonp-without-any-3rd-party- libraries.
CHAPTER 10: Integrating with Social APIs