Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.json, d3.xhr and cross-domain problems

I made several tests today related to the way we can load json files with d3 because I was intrigued by this question: d3.json works but $.getJson fails. However some of the tests that I made are a little bit tricky.

d3.xhr("http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&query=select+*+where+%7B%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FRoger_Federer%3E+%3Fp+%3Fo+filter%28lang%28%3Fo%29+%3D+%27en%27%29%7D%0D%0A&debug=on&timeout=&format=application%2Fsparql-results%2Bjson&save=display&fname=", function(data)
console.log("success1"); 
alert(data);
});

d3.json("http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&query=select+*+where+%7B%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FRoger_Federer%3E+%3Fp+%3Fo+filter%28lang%28%3Fo%29+%3D+%27en%27%29%7D%0D%0A&debug=on&timeout=&format=application%2Fsparql-results%2Bjson&save=display&fname=", function(data){              console.log("success2");
alert(data);
});


d3.xhr("http://api.worldbank.org/countries/BRA/indicators/BX.KLT.DINV.CD.WD?per_page=10&date=2007:2012&format=json", function(data){
console.log("success3");
alert(data);
})

d3.json("http://api.worldbank.org/countries/BRA/indicators/BX.KLT.DINV.CD.WD?per_page=10&date=2007:2012&format=json", function(data){
console.log("success4");
alert(data);
})

I know that the problem can be related to at least 2 reasons: MIME type and CORS, but I can't understand several other things:

  1. if the callback is always executed (even tough sometimes with the OK 200 which can also be an error as seen from jQuery's .ajax() and .getJSON() methods) why can I see the data in only one case (the first one) - the rest of the cases are always errors?

  2. what are the MIME types supported by d3.xhr method?

  3. if d3.json was just a nice wrapper for d3.xhr why does example 1 works and example 2 doesn't work...? I would like some clarification. I mostly use d3 with files from my server, but there are cases like this when I also have to use some external data, and it would be really nice to do this also with D3, not just with jQuery.

I think there should be a list with all the MIME types accepted by these methods.

like image 769
paxRoman Avatar asked May 16 '12 22:05

paxRoman


1 Answers

The reason why the first request succeeds while the second fails has to do with a configuration of the dbpedia.org server. The d3.json() function does two things:

  1. It sets the Accept header to the mimetype application/json

  2. It parses the response using JSON.parse()

Number 1 is the issue - the dbpedia.org server is returning a response of 406 (Unacceptable) for the Accept: application/json header. I'm not sure why this is true, but given the URL parameters you're sending, it looks like the server expects application/sparql-results+json instead - indeed, specifying this mime-type with d3.xhr() succeeds, while using application/json fails.

With the World Bank data, the request fails because the server is not CORS-enabled. The only in-browser way to make a call to a remote API without CORS enabled is to use JSONP (assuming the API supports it). As it happens, data.worldbank.com does support JSONP, but D3 does not - you'll need to either deal with it yourself or use a 3rd-party library like jQuery to make the request.

In general, D3 has not prioritized really robust AJAX support the way that jQuery and other libraries have, because that's not its focus - so if you want to load a wide variety of external resources, you should probably do so with a 3rd-party library that has more support for carefully tweaked AJAX calls. Depending on what you want to load, the other option is to set up a proxy on your own server that can call the remote APIs and then give the data back to your visualizations via a local HTTP call - in which case all of D3's loaders should work fine.

like image 135
nrabinowitz Avatar answered Oct 22 '22 07:10

nrabinowitz