Friday, October 21, 2011

Using Google+ API - The Real One - Part 2. Ajax, Paging and Commenting

In the first installment of my blog series about using the real Google+ API, I have described how to retrieve a Javascript structure, representing messages by parsing a Google+ page source. This was a good introduction, buty there is a better way to retrieve a message stream - by calling Google+ server directly using Ajax calls. This method of communicating with Google+ is better than screen scraping described before, because it allows you to get more than the first page of messages

The Message Stream Ajax Call URL

In order to retrieve a message stream from Google+, perform a HTTP GET request to this URL:

https://plus.google.com/_/stream/getactivities/?sp=[1,2,null,circleid,null,20,null,"social.google.com",[]]&rt=j&ct=token

In order to overcome the potential problem with caching (Internet Explorer tends to return cached version of the server response instead of actually contacting the server), you will want to append a dummy timestamp parameter to the request, like this:
'&_requid=' + new Date().getTime()
There are three important parameters of the call, which let you control what gets returned. I have marked these in red color in the URL above. 

  • The first one - circleid - is the identifier of the circle, from which you want to retrieve the message stream. If you want to retrieve messages from "all circless", set this to null. Otherwise, you will have to know the ID of the circle you want to retrieve messages from. I will show you how to retrieve information about circles in the next installment of this series
  • the second parameter in red is the page size. The default is 20 messages, but you can set this to something else, depending on your needs
  • the third parameter - &ct=token - is the "page token" of the page of message stream that you want to retrieve. This is an optional parameter - you should omit it if you want to retrieve the first page. Otherwise, you have to know what the page token of the page that you want to retrieve is. I will describe this in more detail below.
Retrieving the Message Stream

Given the URL above, you can execute the following jQuery to retrieve message stream:
var frontGarbage = "Invalid JSON: )]}'"; 
jQuery.support.cors = true;
 jQuery.ajax({
        type: 'GET',
        url: url,
        error: function (xhr, status, error) {
            if (error.indexOf(frontGarbage) == 0) {
                var response = jQuery.parseJSON(error.substring(frontGarbage.length));
            }
        }
    });
Before we dig into what is the content of response , I first need to explain two things:
  • why is the response retrieved in the error handler and not in the success handler of the jQuery Ajax call? 
  • what is frontGarbage?
The answer is - the first is the consequence of the second. Google+ server, in all its wisdom, prefixes the proper JSON response of the message stream (and pretty much of any response that it returns to the callers) with the garbage text. This is probably an attempt to make my life more difficult. As a result of this, jQuery is unable to automagically parse the response as JSON and decides that the server errored. Fortunately, it gives us the full server response in the error parameter, allowing us to parse the JSON manually
Now, on to the response data. The majority of it, namely response[0][1][1][0] is the message table containing messages in the exact same format as described in my previous post. You can interpret it in the same way, no modifications required.

There is an additional important parameter in the response: response[0][1][1][1]. It is a pretty long string of hexadecimal characters, which constitutes the "next page token" value for a page that you have just retrieved. Which means that if you pass this value as the ct parameter of the Ajax call's URL, you will get the next page of messages. Curiously, there does not seem to be a "previous page token" anywhere in the response. Which means that you have to remember the already retrieved tokens in some kind of a table, and use the correct one to move back and forth between the message stream pages

Adding Comment To The Post

Now let's concentrate on a stuff that is actually absolutely impossible in the current incarnation of the Google+ API. Which is - let's modify something in the message stream, which the official API does not let you do, because it is a read-only API.

Before we begin - you may be wondering now, why I have described two methods of retrieving a message stream: by screen scraping the HTML page, and by means of an Ajax call. The reason for this is that in order to perform any sort of non-read-only operation, you need to know the XSRF token. Otherwise, Google+ server will reject the call (and rightfully so - we don't want Google+ to be insecure, do we?). For obvious reasons, the XSRF token cannot be obtained by an Ajax call - it has to be contained on a page. So to get to the token required to modify a message on Google+, you have to do the following:

  1. obtain the URL of the message (the post[21] described inthe previous post contains the URL - you will need to prepend https://plus.google.com to this value)
  2. screen-scrape the page to obtain its message data, as described in the previous post
  3. the pageData[1][15] is the XSRF token that you want
After every non-read-only operation, you will hav eto obtain a new XSRF token again. The simplest way to do it is to repeat step 2 and 3. But typically, the next XSRF token is also present in all server responses from state-modifying operations. Identifying these is left as an excercise to the reader (Firebug is your friend here).

Now that we have the required XSRF token, posting a comment to the Google+ message is very easy
jQuery.support.cors = true; 
var data = 'itemId=' + postId + '&text=' + encodeURIComponent(text);
data = data + '&clientId=os:' + postId + ':' + new Date().getTime();
data = data + '&at=' + encodeURIComponent(xsrf) + '&' 
jQuery.ajax({
        type: 'POST',
        url: 'https://plus.google.com/_/stream/comment/?_requid=' + new Date().getTime() + '&rt=j',
        data: data,
        error: function (xhr, status, error) {
                if (error.indexOf(frontGarbage) == 0) {
                    // this is a success
                } else {
                    // this is a failure. You may want to display some error message
                }
        }
    });

The important elements of this code are

  • postId - this is the post ID described in the previous post. It is contained in the post[8] element of the message structure
  • text - this is the text of the comment that you want to post

To Be Continued

In the next installment, I will describe how to:
  • retrieve a list of circles
  • add or remove a +1 to the post



No comments:

Post a Comment