JSONP is a way to fetch JSON data from a different domain, often in an asynchronous way, but without being restricted by the browser’s same-origin policy like you would be with XMLHttpRequest
. But perhaps you only know it via a library like jQuery, which auto-magically handles JSONP URLs. Here’s a simple JSONP example and breakdown to show what’s really going on behind the scenes.
I was recently quizzed on JSONP and how it works, and my response was something like, mumble … mumble … callback … mumble … use other dudes’ JSON. Okay, maybe not as caveman-like as that, but it wasn’t a great answer.
My experience with JSONP until then had been exclusively through jQuery. jQuery.getJSON()
magically switches to JSONP mode when you have a callback parameter in your JSON URL, so what did I care what it was doing under the covers? Something ajax-y and magical. Well, it’s time to learn more.
The simplest JSONP example EVAR
JSONP is actually really simple, so let’s just look at some code. Here’s a working example in six lines:
<script>
function processJSON (json) {
// Do something with the JSON response
};
</script>
<script src='http://api.flickr.com/services/feeds/photos_public.gne?
jsoncallback=processJSON&tags=monkey&tagmode=any&format=json'></script>
First, we see processJSON()
is a Javascript function that we’ve defined in our own code before the Flickr script is called.
Next, note the jsoncallback=processJSON
query param in the Flickr API URL. This tells it to return its JSON “padded” inside a Javascript function call that corresponds to the name of our already-defined function. (The server needs to support this special query param, of course.)
Upon running this code, a request will be sent to Flickr, and the response will look like:
processJSON( {
"title": "Recent Uploads tagged monkey",
"link": "http://www.flickr.com/photos/tags/monkey/",
"description": "",
"modified": "2015-02-03T21:23:22Z",
"generator": "http://www.flickr.com/",
"items": [
// ... Much more JSON here ...
]
} )
Finally, because Javascript called via the script
tag isn’t subject to the browser’s same-origin policy, the response will simply be executed in the browser with our processJSON()
function, with the JSON data passed as its argument.
At that point, you do whatever you need to do with the JSON in your function: parse it, filter it, ask it out on a date, etc. You might recognize this as a callback pattern, i.e. after the API request has finished, we tell it to “call us back” via processJSON()
with the results.
Breaking it all down
The core elements of JSONP, then, are as such:
- A callback function defined on your site.
- A request to the remote API via
<script>
tag:- Includes a special param providing the name of your callback function
- The response:
- Is just Javascript
- That consists of:
- A function call, the name of which you specified in the request
- With the argument being the JSON data of interest
- Gets executed immediately, as if it were called from your own domain
This callback arrangement between you and the server, combined with avoiding same-origin restrictions, is really the whole trick to JSONP. And as you may have guessed by now, the function padding around JSON data is why it’s called JSONP.
Fundamentally, that’s all that’s going on! Check out the working jsFiddle example.
Making it asynchronous
Now, you don’t absolutely need it to be, but asynchronicity is nice for the consumption of third-party data because it lets us execute code in a way that doesn’t block the page load. One way to do this:
<script>
function processJSON (json) {
// Do something with the JSON response
};
// Create a new script element
var script_element = document.createElement('script');
// Set its source to the JSONP API
script_element.src = 'http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=processJSON&tags=monkey&tagmode=any&format=json';
// Stick the script element in the page <head>
document.getElementsByTagName('head')[0].appendChild(script_element);
</script>
Adding a script
element to the page like this won’t block other components during download. In fact, behind the scenes of jQuery’s getJSON()
, this is basically what’s happening; in the case of a JSONP call, XMLHttpRequest
is never actually coming into play. jQuery just does some fudging to make it behave like any other true ajax request.
Of course, in practice, jQuery’s JSONP implementation is a little more complex than these examples. But now you have an understanding of the basics.
More reading
- Wikipedia: JSONP
- Wikipedia: CORS (an alternative to JSONP)
- IBM developerWorks: Cross-domain communications with JSONP