11 January 2015

JSONP Clarified

JSONP stands for "JSON with padding". JSONP is a means of passing Javascript expressions cross-origin. It is an alternative way to fetch data that can bypass the same-origin policy in a way normal AJAX calls cannot. JSONP allows us quick cross-domain usage of APIs, but has the disadvantage of being unable to perform error checking in older browsers. It also disallows us from making POST request. Only cross domain calls which result with the evaluation of received data using Javascript in the browser require JSONP. Interfaces which implements CORS do not require JSONP. For example, Twitter API and Google Maps API do not require JSONP. Another disadvantage of JSONP is it leaves your application vulnerable to XSS attacks by the foreign origin you are requesting from. If the remote end of the JSONP source isn't trusted, your application is open to an XSS attack.

How to use JSONP

I recently had to use an API in order to retrieve weather data. In doing so I learned all about the restrictions incurred by the same-origin policy and how to get around it using JSONP. JSONP allows developers to get around the same-origin policy. JSONP takes advantage of the fact that the <script> tag does not need to abide by the same-origin policy. We can create a <script> tag and set it's src attribute to our API endpoint. Additionally, we can even specify options right there in the src url, such as the return format and the callback to be triggered right there in the src attribute.

app.coffee

script = document.createElement("script")
script.src = "http://api.worldweatheronline.com/free/v1/weather.ashx?q=#{query}&format=json&callback=processWeather&key=j8xvysb7t9jp2dvw7pwcbgs3"
document.body.appendChild(script)

Notice the callback=processWeather code in the src attribute. This callback option makes it so when the data is retrived from the API then that callback is called with the return data. All we need to do is declare the callback function in app.coffee.

app.coffee

window.processWeather = (weather) ->
  if weather.data.error
    #do stuff
  else
    #do some other stuff

Nuances of Scoping in CoffeeScript

Notice that I declared processWeather on the window object. I had to do this because CoffeeScript wraps all code inside an anonymous function when it compiles into JavaScript. Since the src attribute that is activating processWeather is calling from outside the app.coffee scope, processWeather needs to be declared on the window object so that it is accessible to the callback.

Using JSONP with AJAX

One way to perform a JSONP request it by using a <script> tag with an embedded callback in it and appending it to the DOM. There exist other ways to perform a JSONP request. One of those other ways is to use ajax. JSONP can be used in conjunction with ajax. All you need to do is create a normal ajax get request and change a few properties of the object you pass in. On the object you pass into the ajax method the dataType property should be set to "jsonp" and the jsonpCallback property should be set to whatever callback you want to use on the response data.

Example

app.coffee

request = (requestType) ->
  {
    url: endpointURL requestType
    jsonpCallback: "displayMovies"
    dataType: "jsonp"
  }

$(document).ready ->
  $('#opening').click ->
    $.ajax request "opening"

  $('#now').click ->
    $.ajax request "in_theaters"

  $('#coming').click ->
    $.ajax request "upcoming"

And bam! JSONP will work with ajax!