40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

node.jsからGoogleReaderにアクセス出来ないか試してみた

GoogleReaderのAPIは公開されているわけではないのですが以前にも何度かお世話になったGoogle Reader APIの叩き方のエントリを読みながら、node.jsからGoogleReaderにアクセス出来ないか試行錯誤しています。

GoogleReaderAPIは以前よりも簡易になった?

非公式GoogleReaderAPIドキュメントの下の方のコメントに

Fixed the auth header function, had to use the auth key and not the previously used SID, also had to add the service key into the request:

ということで、以前だったらhttp ヘッダーにSIDとかトークンというものをセットしていました。

以前試したことのあるRubyのgooglebaseというgemのソースを見る限りたしかにSIDセットしているようですがためしにcurl使って

curl -k https://www.google.com/accounts/ClientLogin -d Email=xxxx@gmail.com -d Passwd=xxxxx -d service=reader

とやると

SID=XXXX(長いので省略)
LSID=XXXX(長いので省略)
Auth=XXXX(長いので省略)

みたいなレスポンスが得られるので、このAuth=の所の文字列をhttpヘッダーに

Authorization:GoogleLogin auth=XXXX(長いので省略)

セットすればOKのようです。

自分が理解したのを絵にするとこんな感じですかね
googlereader

http client的なものの準備

自分で全部作るほどのレベルではないので、GData にだってアクセスできるんだぜが参考になりそうなので、こちらをお手本にすることにしました。

とりあえず動くものは出来たので、近いうちにソース晒します

ソースはこんな感じ

/**
 * Google Account Login Client
 */

var Client = function(params){
  this.HOST = "www.google.com";
  this.http = require('http');
  this.querystring = require('querystring');
  this._httpsClient = this.http.createClient(443, this.HOST, true);
  this._httpClient = this.http.createClient(80, this.HOST, false);

};

Client.prototype= {
  login : function(email, password, service){
   if( service == undefined ){
      throw 'service parameter must be specified.';
   }
   var EventEmitter = require("events").EventEmitter;
   var event = new EventEmitter();
   var self = this;
   var params = {
      'accountType': 'HOSTED_OR_GOOGLE',
      'Email' : email,
      'Passwd' : password,
      'service' : service
   };
   var body = this.querystring.stringify(params);
   var req = this._httpsClient.request(
      'POST', '/accounts/ClientLogin',
      {
         'Content-Type': "application/x-www-form-urlencoded"
      }
   );
   req.write(body);
   req.on('response', function(res){
      var body = '';
      res.on('data', function(chunk){
         body += chunk;
      });

      res.on('end', function(){
         var obj = {};
         var lines = body.split('\n');
         for(var i in lines){
            var l  = lines[i];
            var kv = l.split('=');
            if( kv.length == 2 ){
               obj[kv[0]] = kv[1];
            }
         }
         if( res.statusCode == 200 ){
            event.emit('success');
	    //get Auth value
	    self.getFeed(self.setHeaders(self.extractAuth(body)));
         }else{
            self._authToken = undefined;
            event.emit('failure');
         }
      });
   });
   req.end();
   return event;
  },//login

  extractAuth:function(body){
    var matches = body.match(/Auth=(.*)/);
    var _result = matches[0].split('Auth=');
    return _result[1];
  },
  setHeaders:function(auth){
    var param ={};
    var _values = "GoogleLogin auth=" + auth;
    param["Authorization"]= _values;

    return param;
  },
  getFeed:function(param){
    console.log('start');
    console.log(param);
    var req = this._httpClient.request(
      'GET', '/reader/api/0/unread-count?all=true',param
    );

    req.end();

    req.on('response', function (response) {
      console.log('wait response');
      console.log('STATUS: ' + response.statusCode);

      console.log('HEADERS: ' + JSON.stringify(response.headers));

      response.setEncoding('utf8');
      response.on('data', function (chunk) {
	console.log('BODY: ' + chunk);
      });
    });
  }
};

var Google = new Client();
Google.login('yourgmailaddress,'password','reader');