Sunday, July 08, 2012

Fixing the Google Analytics API (v3) examples


I'm currently working on consuming data from the Google Analytics API for one of the data sources we're using at Eysys.

So far, so normal. But what was strange was the poor state of the Google Analytics API documentation. I don't think I've ever seen one of their APIs be documented so poorly - missing source code, typos in example source code provided, a real rambling tone to the docs pointing off to different areas (a lot of this is to do with the OAuth 2.0 hoops you have to jump through before even starting to pull down the data you want to analyse).

I also couldn't believe how many dependencies the API has - I ended up with 29 jar files in my Eclipse project's lib folder! Surely this could all be a lot leaner, meaner and easier - it's just an API returning JSON data at the end of the day..

Anyway, if you're interested in getting up and running with the API examples, here's what to fix.

First of all, there is actually missing source code in the distro itself (or at least the one I used - google-api-services-analytics-v3-rev10-1.7.2-beta.zip), so you need to get LocalServerReceiver, OAuth2Native and VerificationCodeReceiver directly from the Google code repo.

LocalServerReceiver uses an old version of Jetty, so we need to migrate it to use the latest Jetty (I used 8.1.4.v20120524) which now has an org.eclipse.* package structure. So we need to update the imports as follows:

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;

Refreshing Jetty will also necessitate upgrading the handle(..) method to fit in with the new signature, as follows:

@Override
public void handle(String target, Request arg1,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (!CALLBACK_PATH.equals(target)) {
return;
}
writeLandingHtml(response);
response.flushBuffer();
((Request) request).setHandled(true);
String error = request.getParameter("error");
if (error != null) {
System.out.println("Authorization failed. Error=" + error);
System.out.println("Quitting.");
System.exit(1);
}
code = request.getParameter("code");
synchronized (LocalServerReceiver.this) {
LocalServerReceiver.this.notify();
}
}


There's also a small mod to be made in getRedirectUri(), change this line:

server.addHandler(new CallbackHandler());

to this instead:

server.setHandler(new CallbackHandler());


The logic of this class also seems pretty flawed to me - generating a random port for the redirect URI that OAuth calls back to at the end of authentication every time it's run, which by definition you won't be able to put into the APIs console. So I commented out the getUnusedPort() method and simply hard-coded one.

And after these mods, hey presto it works! :-)

1 comment:

Mainak Goswami said...

I completely agree with you. The Google API is very poorly documented. I had to struggle to find an end to end link.
I felt their structuring is difficult as well. They tend to refer multiple documents but forget to structure them as an index. Same is with their OAuth and Analytics usage documentation.