Jump to Table of Contents

JSONP

The JSONP Utility is a specialized API for communicating with web services that provide JSON responses wrapped in a callback function. A typical JSONP request URL might look like "http://example.com/service.php?callback=handleData" and receive a text response in the form of handleData({"records":[....]});.

The nature of YUI 3's sandbox model complicates JSONP transactions because JSONP relies on a global access point to process the response, but YUI 3 implementation code is typically wrapped in a use(...) callback and is therefore not globally accessible. The JSONP module provides a proxy system for channeling JSONP responses back into your YUI instance sandbox.

Security Note: JSONP is an inherently unsecure communication method, since it involves the transfer of unvalidated JavaScript. It is by convention alone that the format is associated with JSON, but in reality, the response can include any arbitrary JavaScript, potentially opening your page to attack. Be cautious about which services you communicate with via JSONP. For safe JSON communication, use the JSON module in conjunction with the IO module wherever possible.

Getting Started

To include the source files for JSONP and its dependencies, first load the YUI seed file if you haven't already loaded it.

<script src="http://yui.yahooapis.com/3.8.0/build/yui/yui-min.js"></script>

Next, create a new YUI instance for your application and populate it with the modules you need by specifying them as arguments to the YUI().use() method. YUI will automatically load any dependencies required by the modules you specify.

<script>
// Create a new YUI instance and populate it with the required modules.
YUI().use('jsonp', 'jsonp-url', function (Y) {
    // JSONP is available and ready for use. Add implementation
    // code here.
});
</script>

For more information on creating YUI instances and on the use() method, see the documentation for the YUI Global Object.

Using the JSONP Utility

Instantiation and the Y.jsonp method

The JSONP utility provides the Y.jsonp(url, callback) method for single transactions as well as a Y.JSONPRequest class to manage reusable connections.

The first argument to either the Y.jsonp method or the Y.JSONPRequest constructor is the URL of the JSONP service, and the second is a callback function or configuration object that contains a callback function. When the service responds with the data, the callback will be executed with the response data as the first parameter.

In place of the JSONP callback name in the URL, include the string "{callback}". This placeholder will be used for a proxy function that will route the data to your callback.

// instead of service.php?callback=handleJSONP
var url = "http://example.com/service.php?callback={callback}";

function handleJSONP(response) {
    // response is a JavaScript object. No parsing necessary
    Y.one("#output").setHTML(response.outputHTML);
}

Y.jsonp(url, handleJSONP);

// or
var service = new Y.JSONPRequest(url, handleJSONP);
service.send();

Sending JSONP requests

Y.jsonp(url, callback) will dispatch the request immediately. JSONPRequest instances will dispatch the request each time their send() method is called.

// request sent immediately
Y.jsonp(url, handleJSONP);

// No request sent
var service = new Y.JSONPRequest(url, handleJSONP);

// ...until now
service.send();

// ...and now again
service.send();

Y.jsonp(url, callback) is a convenience wrapper to instantiate a JSONPRequest instance and call its send() method.

This will generate a request to a URL like this one (note that the {callback} placeholder has been replaced with a dynamically generated callback name):

http://example.com/service.php?callback=YUI.Env.JSONP.yui_3_3_0_1_1294184187597423

The server will then be expected to respond with a JavaScript value wrapped in a call to that function, like this:

YUI.Env.JSONP.yui_3_3_0_1_1294184187597423({"foo":"bar"});

Configuring the connection

The second argument to either Y.jsonp or the Y.JSONPRequest constructor can be a success callback function or for more control, it can be a configuration object. The supported keys of this object are:

Property Description
timeout This value, defined as milliseconds, is a time threshold for the transaction (e.g., { timeout: 2000 } ). When this limit is reached, the transaction's on.timeout callback will be executed if supplied.
context Defines what will be "this" in the callbacks. If undefined, the default will be the JSONPRequest instance.
args An array of additional arguments that will be passed to the callbacks as second, third, and so on arguments.
on

Required. This object defines the callbacks to be used for the transaction. At least an on.success handler must be defined.

  • success (required)
  • failure
  • timeout
format Preprocessor function to stitch together the supplied URL (first argument), the proxy function name (internally generated), and any additional arguments passed to send(). See Customizing the JSONP URL for more detail.

This is an example of a configuration object, with a set of properties defined.

var url     = "http://example.com/service.php?callback={callback}",
    service = new Y.JSONPRequest(url, {
        on: {
            success: MyApp.handleJSONP,
            timeout: MyApp.handleTimeout
        },
        context: MyApp
        timeout: 3000,          // 3 second timeout
        args: [new Date(), 100] // e.g. handleJSONP(data, date, number)
    });

service.send();

// or
Y.jsonp(url, {
    on: {
        success: MyApp.handleJSONP,
        timeout: MyApp.handleTimeout
    },
    context: MyApp
    timeout: 3000,          // 3 second timeout
    args: [new Date(), 100] // e.g. handleJSONP(data, date, number)
});

Parsing the callback from the URL

An extension for the jsonp module is the jsonp-url module which provides a few additional features.

  1. If you have a global function or a function available from the YUI instance (e.g. Y.MyApp.handleJSONP), you can include the name in the URL and omit the second parameter entirely.
  2. The URL passed as the first parameter need not include the "{callback}" string. If it is not found, it will look for "callback=", then fall back to adding the query parameter onto the URL.
Y.MyApp.handleJSONP = function (data) {
    Y.one("#output").setHTML(data.outputHTML);
};

Y.jsonp("http://example.com/service.php?callback=Y.MyApp.handleJSONP");

// or
Y.jsonp("http://example.com/service.php", {
    context: Y.MyApp,
    on: {
        success: Y.MyApp.handleJSONP,
        failure: Y.MyApp.handleFailure
    }
});

Customizing the JSONP URL

The default URL formatter simply replaces the "{callback}" placehold with the name of the generated proxy function. If you want to customize the URL generation process, you can provide a format function in the configuration. The function will receive the configured URL (with "{callback}" placeholder), the string name of the proxy function, and any additional arguments that were passed to send().

// Our custom formatter will expect a URL with an additional placeholder for
// username that must be supplied in send("bill");
// e.g. http://example.com/bill/json?fn=YUI.Env.JSONP._12345
function prepareJSONPUrl(url, proxy, username) {
    return Y.Lang.sub(url, {
        callback: proxy,
        name: username || "user"
    });
}

var url = "http://example.com/{name}/json?fn={callback}";

var service = new Y.JSONPRequest(url, {
        format: prepareJSONPUrl,
        on: {
            success: handleJSONP
        }
    });

service.send("apipkin");
service.send("tivac");
service.send("razass");

Known Issues

  • Unlike the XMLHttpRequest calls generated by the IO utility, JSONP requests can't be aborted, since they rely on dynamic script insertion (which provides less low-level control than XHR). Keep this in mind when deciding which method to use.
  • Since most browsers don't enforce execution order for dynamically inserted scripts, JSONP callbacks may not be called in the same order that the requests were sent. On the other hand, some browsers do enforce execution order, so in these browsers a slow request may block the execution of subsequent JSONP callbacks.
  • In WinJS (Windows 8 application mode), JSONP is not supported due to the security measures enforced in that environment. Making a JSONP request requires a remote script tag which is prohibited. An alternative is to use the YQL module to query a YQL table that can return the data that you need. The YQL module is supported in this environment because it uses native XMLHttpRequest to fetch it's data.