What is JSONP?

July 3, 2013

Introduction

Today I was asked for some help with understanding the difference between JSON and JSONP, and how to apply the two, so this is a good opportunity to go over some things about how JSON and JSONP are used for AJAX requests, and why issues of security result in some difficulties.

The problem of security

JSONP is a response to wanting to get data from a different website, without exposing yourself to cross-domain security risks. A problem that websites have to face is that someone might add a comment and embed <script> tags within that comment which retrieve code from some other domain, normally for bad purposes. Potentially making things even less secure, is that XMLHttpRequest allows a script to send information at any time, so to help limit the scope for abuse, XMLHttpRequest is restricted to communicating only within the same domain of the page. JSON is a simple data format, expressed using JavaScript objects and arrays, where a script uses XMLHttpRequest to perform an AJAX request that to retrieves information from somewhere else within your domain. This allows the page to obtain the information that it needs without having to reload the page or load up a new page.

Contacting new worlds

But what happens when you require information from somewhere outside of your domain? JSONP is a standard that provides a safe way to do that. A <script> tag on your page is allowed to request information from another domain, for example:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.js">
</script>

but <script> tags must contain valid scripting code, not data. If just JSON data is loaded then that would result in a syntax error. So a function call is wrapped around the data so that the data can then be passed to that function, and processed.

A JSON request

A request from http://www.example.com/get/data might result in the following JSON data:

{
 "firstName": "John",
 "lastName": "Smith",
 "address": {
 "streetAddress": "21 2nd Street"
 }
}

But if the above JSON data is loaded in to the <script> tag though, it wouldn’t be valid scripting code. It needs to be either assigned to a function, or passed as an argument to a function.

Wrapping up with JSONP

How JSONP helps to solve the problem is to let your page pass the data to a function. You supply the name of a function name on your page that will handle the data, and the site from where you are requesting the data will wrap the name of your function around the JSON code. This means that the request for JSONP data then becomes: http://www.example.com/get/data?jsonp=parseResponse

parseResponse({
 "firstName": "John",
 "lastName": "Smith",
 "address": {
 "streetAddress": "21 2nd Street"
 }
});

It’s important to note that not all data feeds support JSONP. The purpose is to only allow such forms of communication where you want another website to be able to access that data. When a data location supports JSONP, it can accept a function name that you give it and wrap it around their data.

Easy handling

So now, as long as you already have a function defined called <code>parseResponse</code>, you can then handle that data without any trouble.

function parseResponse(data) {
 // do stuff with data
 // ...
}

Because there is a potential for security trouble if you always use the same name, libraries such as jQuery use a different name each time.

An example with flickr

What would this look like in actual practice? With jQuery we can come up with a nice and simple example, because jQuery automatically provides a callback function name and passes any response on to the done section of the script. This example uses JSONP to retrieve images and show the first 4 images (counting from 0 to 3) from the public flickr feed, by adding them to an images section on the web page.

var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
$.getJSON(flickerAPI, {
 tags: "mount rainier",
 tagmode: "any",
 format: "json"
})
.done(function(data) {
 $.each(data.items, function(i, item) {
 $("<img alt="" />").attr("src", item.media.m).appendTo("#images");
 if (i === 3) {
 return false;
 }
 });
});

The above example can be seen in action at http://jsfiddle.net/pmw57/S69YU/ where you can play around with it as well.

Advertisements

Getting elements by class name

February 2, 2010

The topic of getting elements by their class name is one that has been covered by many people, but nothing seems to put together all of the information in such a way that it works across most of the web browsers out there.

Within the past couple of years, modern web browsers have added their own native getElementsByTagName that is incredibly fast, when compared with using a script. Other web browsers such as Internet Explorer do not have a native implementation, so still require a scripted solution for these other browsers. Here’s how to achieve that in a cross-browser manner.

Even though there are a wide variety of getElementsByTagName scripts that people have created, many of them only partially resolve the issle. Ultimately there are two major issues at hand:

  1. Detecting whether a browser already has a getElementsByTagName implementation
  2. Limit the search by tag name, to assist slower web browsers

The first issue is nicely resolved thanks to advice from Sid Robert’s blog

Due to a number of compatibility issues with different web browsers, we need to assign the script to both Object.prototype and document. As we don't want to overwrite the native implementation of getElementsByTagName, we'll use the || operator to attempt to assign the native implementation first so that if that fails, the anonymous function that follows it can be used instead.

Object.prototype.getElementsByClassName = document.getElementsByClassName =
    document.getElementsByClassName || function (searchClass, tag) {

John Resig has a getElementsByTagName Speed Comparison that lists many of the popular getElementsByTagName functions. For this post I have chosen to use the one by Dustin Diaz, which has the fastest DOM implementation. This function is compatible back to IE6. In order to be compatible with IE5 we would need to use a different technique to obtain all of the tags, as using '*' with getElementsByTagName fails to work in IE5.

A few updates have been made to this function so that things like unspecified arguments are correctly detected, and that issues that might be picked up by JSLint are tidied up.

This is the cross-browser compatibility script for getElementsByClassName

Object.prototype.getElementsByClassName = document.getElementsByClassName =
    document.getElementsByClassName || function (searchClass, tag) {
    if (tag === undefined) {
        tag = '*';
    }
    var classElements = [],
        els = this.getElementsByTagName(tag),
        elsLen = els.length,
        pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"),
        i, j;
    for (i = 0, j = 0; i < elsLen; i += 1) {
        if (pattern.test(els[i].className)) {
            classElements[j] = els[i];
            j += 1;
        }
    }
    return classElements;
};

With the above script running before other code that uses el.getElementsByClassName, you can now safely ensure that your code will run successfully on a wide range of web browsers.


Getting to the next element

January 15, 2010

Traversing the HTML DOM to get to the next element can be a tricky business.

Take the following list as an example:

<ul>
    <li>First item</li>
    <li>Second item</li>
    <li>Third item</li>
</ul>

Internet Explorer considers that there are only three nodes within the UL tag (the LI elements), whereas virtually all other modern web browsers consider that there are seven nodes within the UL element.

Three of the nodes are the LI elements, and the other four are text nodes, the whitespace between the tags, which consists of spaces, tabs, and newlines.

Text elements can also easily be normal text though. Consider the following:

<p>Some text with <a href="link.html">a link</a>.</p>

This paragraph contains two text nodes and an A element, which itself contains a text node.

#text "Some text with "
A
  #attr href="link.html"
  #text "a link"
#text "."

It is this difference between modern web browsers and Internet Explorer, that causes trouble when using direct node relationships such as the nextSibling property.

In many cases you can avoid this problem by using other techniques. With the unordered list for example, you can assign the UL element to a variable called el and use document.getElementsByTagName('li') to get all of the LI elements.

There can be times though when you need to step forward to the next element and avoid text nodes. As the nodeType of text elements is 1, and the nodeType of HTML tags is 3, we can use that as the basis for a useful tool.

function nextElement(el) {
    el = el.nextSibling;
    while (el && el.nodeType === 1) {
        el = el.nextSibling;
    }
    return el;
}

Conclusion to sliders

January 13, 2010

Now that scripting the slider regions is done, we have a finished and functional slider for our forms.

This post is part of a series that guides you through creating robust sliders for your forms.

Read the rest of this entry »


Scripting the slider regions

January 12, 2010

Now that we have connected the slider to the form, we can provide some added enhancement by showing in bold the appropriate region description underneath the slider.

This post is part of a series that guides you through creating robust sliders for your forms. Read the rest of this entry »


Creating the sliders

January 11, 2010

When creating our sliders, the changes that we want to make are:

  • add an empty div to contain the slider
  • add some region descriptions beneath the slider
  • hide the input field

This post is part of a series that guides you through creating robust sliders for your forms. Read the rest of this entry »


Basic requirements for sliders

January 11, 2010

When scripting is available,  we can update the form to provide sliders for our questions. Before that happens though, we need to add the jQuery UI library to the head of the page, which does much of the slider work for us.

This post is part of a series that guides you through creating robust sliders for your forms. Read the rest of this entry »