JSONP with Dart

A few people have asked how to handle JSONP in Dart. Turns out, this is basically possible, and I'd appreciate feedback on this technique.

JSONP is a trick to get around the lack of CORS headers in your favorite API. CORS is the modern way to get around the single origin policy, however even Google still doesn't support CORS on many of their APIs. The web developer community has come up with JSONP as a hack until all browsers and all APIs support CORS.

Option 1: If you always deploy to JavaScript

This method only works if you are always deploying to JavaScript and are not deploying or testing on Dartium (Chromium with an embedded Dart VM). Also, this feels hacky.

Add the JSONP callback to your main page as a small JavaScript method.

<script type="text/javascript">
function callbackForJsonpApi(data) {
  dartCallback(JSON.stringify(data));
}
</script>

This simple method converts the data from the server into a big JSON string. It passes this string to dartCallback, which happens to come from the JavaScript generated by your Dart program.

Your Dart code should look like this:

#import('dart:html');
#import('dart:json');

dartCallback(String data) {
  var obj = JSON.parse(data);
  print(obj['responseData']);
}

void main() {
  // this pulls in the function to ensure
  // it's compiled into the resulting JavaScript
  var f = dartCallback;
  
  Element script = new Element.tag("script");
  script.src = "https://ajax.googleapis.com/ajax/services/search/news?v=1.0&q=barack%20obama&callback=callbackForJsonpApi";
  document.body.elements.add(script);
}

This tricky hack takes advantage of the fact that the Dart top level functions are translated to JavaScript functions with the same names.

Pros: Simple to understand.
Cons: Doesn't work in Dartium, may not work in the future (if the JavaScript compiler starts to munge names).

Option 2: If you deploy to Dartium and JavaScript

Dartium is Chromium with an embedded Dart VM. Dartium is able to run native Dart code, without any compilation to JavaScript. If you are developing and testing on Dartium (as many of us do), you will need another option for emulating JSONP.

First, add this small snippet of JavaScript to your main page.

<script type="text/javascript">
function callbackForJsonpApi(s) {
  window.postMessage(JSON.stringify(s), '*');
}
</script>

Notice the use of postMessage() to communicate the JSON string data. Using postMessage is how you can send data between the JavaScript world and the Dart world in Dartium.

#import('dart:html');
#import('dart:json');

dataReceived(MessageEvent e) {
  var data = JSON.parse(e.data);
  print(data['responseData']);
}

void main() {
  // listen for the postMessage from the main page
  window.on.message.add(dataReceived);
  
  Element script = new Element.tag("script");
  script.src = "https://ajax.googleapis.com/ajax/services/search/news?v=1.0&q=barack%20obama&callback=callbackForJsonpApi";
  document.body.elements.add(script);
}

The Dart app listens for messages and delegates to dataReceived. Once parsed from the JSON string into an object of Maps and Lists, the Dart program can now operate on the data sent from the JSONP service.

Pros: This option works in both Dartium and when compiled to JavaScript.
Cons: More complicated, possibly slower due to sending large strings over postMessage.

Summary

Accessing a web service that uses JSONP with Dart is possible. For maximum compatibility, use postMessage to communicate between the JavaScript callback and the Dart application.

Please add your comments about this technique, and let us know which JSONP services are you mashing up with Dart.

Thanks for trying Dart!


6 comments

Popular posts from this blog

  • Sponsor:  Register today for  New Game, the conference for HTML5 game developers . Learn from Mozilla, Opera, Google, Spil, Bocoup, Mandreel, Subsonic, Gamesalad, EA, Zynga, and others at this intimate and technically rich conference. Join us for two days of content from developers building HTML5 games today. Nov 1-2, 2011 in San Francisco.  Register now ! This is the second article in a Box2D series, following the Box2D Orientation article. The Box2DWeb port of Box2D contains a nice example to show off the basics of integrating physics simulations into your web app. This post will provide a walkthrough of the example, explaining the high level concepts and code. First, let's see the example in action. The code for the above is open source and available on GitHub. It was adapted from Box2DWeb's example . Animating Before we look at Box2D, it's important to understand how the above simulation is animated. You might think setInterval or setTimeout is
  • In which I port a snazzy little JavaScript audio web app to Dart , discover a bug, and high-five type annotations. Here's what I learned. [As it says in the header of this blog, I'm a seasoned Dart developer. However, I certainly don't write Dart every day (I wish!). Don't interpret this post as "Hi, I'm new to Dart". Instead, interpret this post as "I'm applying what I've been documenting."] This post analyzes two versions of the same app, both the original (JavaScript) version and the Dart version. The original version is a proxy for any small JavaScript app, there's nothing particularly special about the original version, which is why it made for a good example. This post discusses the differences between the two implementations: file organization, dependencies and modules, shims, classes, type annotations, event handling, calling multiple methods, asynchronous programming, animation, and interop with JavaScript libraries. F
  • Angular and Polymer, sitting in a DOM tree, B-i-n-d-i-n-g. First comes components, Then comes elements, Then comes the interop with the node dot bind. Angular , a super heroic MVC framework, and Polymer , polyfills and enhancements for custom elements built on top of Web Components, can live harmoniously in the same app. This post shows you how to connect Angular-controlled components to Polymer-controlled elements via data binding. And we do it all in Dart . Angular and Polymer I get asked "Should I use Angular or Polymer?" a lot. My answer is, "Yes". That is, both libraries have distinct strengths, and you can use both in the same app. Polymer excels at creating encapsulated custom elements. You can use those custom elements in any web app or web page, regardless if that app is built with Angular, Ember, etc. Angular excels at application engineering, with dependency injection, end-to-end testability, routing, and services. Here are som