JSONP, which stands for "JSON with Padding" (and JSON stands for JavaScript Object Notation), is a way to get data from another domain that bypasses CORS (Cross Origin Resource Sharing) rules.
CORS is a set of "rules," about transferring data between sites that have a different domain name from the client. For the purposes of this article, what you need to know is that in older browsers without CORS, and in newer browsers, without configuring things a specific way on both the sending and receiving sides, you can't make an AJAX request to a domain that is different from the one you're sending it from.
Enter JSONP. It pre-dates CORS, and was created as a pseudo-standard way to retreive data from a different domain. It has limitations to the modern full implementation of CORS as it can only really be used to retrieve data, and isn't really appropriate for a creating, updating or deleting data. It's only a retrieval method. While limiting, it definitely has its uses. For example, you can query the Yahoo Weather Service to get the current weather, and use JSONP and it will work on just about any browser with no extra configuration.
Ok, so what exactly is JSONP?
So in a typical request, you request data from the server and it might return some JSON so you can do something with it. On the server's side, JSONP is very similar, only it wraps that JSON in a function.
For example, if the JSON request was:
[{
"id": 1,
"name": "Cameron"
}]
a JSONP request might look like:
someCallback([{
"id": 1,
"name": "Cameron"
}]);
That someCallback
function name is usually specified in the URL via a query parameter, most commonly callback
. So if I add ?callback=cb
to a request that supports JSONP, I'll get JSON wrapped in a function called cb()
.
On the Client Side
So nothing really different/all that special on the server side. At this point, you may be wondering, "how does wrapping some JSON in a function magically make it allowed to be accessed from another domain?" Well, it doesn't.
Where things get "magical" lies with the fact that a regular <script>
tag does not have any limitations as to which domains it can pull down a script from. I could put a link to a JavaScript file on another domain in a <script>
tag and it will download and immediately execute that script.
So if you wanted to implement some JSONP on the client, you'd put that URL in a script tag, and make sure you have a function that matches your callback function somewhere in your code, and that function will be called with the JSON from the request because it's being passed to the callback function that gets executed when the <script>
tag executes.
Kind of a clever hack, eh? I know a lot of people (me included) that have used JSONP a lot without understanding what was going on.
Here is a very simple demonstration on how you would implement this in "vanilla" JS:
See the Pen JSONP Simple Demo by Cameron Spear (@CWSpear) on CodePen.
How the Libraries Do It
Of course you'd want a way to specify a custom callback function, and probably a tighter integration so you can handle the "request" the same way you'd handle a regular GET request. JSONP is integrated into a number of Libraries, such as jQuery or Angular's $http
service.
For example, using Angular, you might create a JSONP request like the one used in the demo like so:
$http.jsonp('http://query.yahooapis.com/v1/public/yql', {
params: {
q: 'select woeid from geo.places where text="' + location + '"',
format: 'json',
callback: 'JSON_CALLBACK'
}
}).then(function (result) {
// result.data contains the
// the response from Yahoo
console.log(result.data);
});
Angular will take the string JSON_CALLBACK
and replace it with a special function that will be unique (Angular uses indexes, jQuery uses timestamps, I believe), thus preventing further pollution in the global namespace, and they will use their special callback function to return the data in a consistent way with a regular $http.get
or $.getJSON
request. No need to even deal with the intermediary callback function, or really change much from a regular GET
, other than specifying a special callback in the query string.
Conclusion
I know this is nothing new, but I had never really considered how JSONP requests worked and found the hack to be quite clever in solving a particular need.
With modern browsers and the new CORS standard, JSONP is being used less and less. It's limited in what it can do, and can be prone to attacks since you're executing code found on another domain. You have to trust that the remote server won't do anything malicious! But it still comes up from time to time, and now you know how it works, and knowing is half the battle.