Google Data on Rails

Google Data API チーム Eric Bidelman
2009 年 2 月

はじめに

クライアント ライブラリのリストの Ruby の場所は?」

Google では、デベロッパーの皆様の強い意欲と Ruby on Rails の長年の人気(RoR)により、同僚の Jeff Fisher が Doom の深い深さから Ruby ユーティリティ ライブラリを構築してきました。本格的なクライアント ライブラリではありませんが、認証や基本的な XML 操作などの基本事項は処理します。また、REXML モジュールと XPath を使用して、Atom フィードを直接操作する必要があります。

対象者

この記事は、Ruby(特に Ruby on Rails)を使用して Google Data API にアクセスすることに関心があるデベロッパーを対象としています。読者は Ruby プログラミング言語と Rails ウェブ開発フレームワークに精通していることを前提としています。ほとんどのサンプルで Documents List API を使用していますが、どの Data API にも同じコンセプトを適用できます。

スタートガイド

要件

Google Data Ruby ユーティリティ ライブラリのインストール

ライブラリを取得するには、プロジェクト ホスティングから直接ライブラリ ソースをダウンロードするか、gem をインストールします。

sudo gem install gdata

ヒント: gem list --local を実行して、宝石が正しくインストールされたことを確認することをおすすめします。

認証

ClientLogin

gclid を使用すると、アプリケーションでユーザーを Google アカウントまたは G Suite アカウントにプログラムでログインできます。ユーザーの認証情報が確認されると、Google は後続の API リクエストで参照される認証トークンを発行します。トークンは、使用している Google サービスによって定義されている一定の期間有効です。セキュリティ上の理由から、また、ユーザーに最適なエクスペリエンスを提供するために、インストール環境でデスクトップ アプリケーションを開発する場合にのみ、OpenSSL を使用してください。ウェブ アプリケーションの場合は、AuthSub または OAuth を使用することをおすすめします。

Ruby ライブラリには、各 API のクライアント クラスがあります。たとえば、user@gmail.com を Documents List Data API にログインするには、次のコード スニペットを使用します。

client = GData::Client::DocList.new
client.clientlogin('user@gmail.com', 'pa$$word')

The YouTube Data API would be:

client = GData::Client::YouTube.new
client.clientlogin('user@gmail.com', 'pa$$word')

実装されたサービスクラスの一覧をご覧ください。サービスにクライアント クラスがない場合は、GData::Client::Base クラスを使用します。たとえば、次のコードを使用すると、ユーザーは G Suite アカウントでログインする必要があります。

client_login_handler = GData::Auth::ClientLogin.new('writely', :account_type => 'HOSTED')
token = client_login_handler.get_token('user@example.com', 'pa$$word', 'google-RailsArticleSample-v1')
client = GData::Client::Base.new(:auth_handler => client_login_handler)

: デフォルトでは、ライブラリは accountTypeHOSTED_OR_GOOGLE を使用します。有効な値は HOSTED_OR_GOOGLEHOSTEDGOOGLE です。

OpenSSL を使用する短所として、ログイン試行の失敗時にアプリケーションに CAPTCHA チャレンジが送信される可能性があることが挙げられます。その場合、client.clientlogin(username, password, captcha_token, captcha_answer) パラメータを追加して clientlogin() メソッドを呼び出すことで、エラーを処理できます。CAPTCHA 処理について詳しくは、インストール済みアプリケーションの認証のドキュメントをご覧ください。

AuthSub

AuthSubRequest URL の生成

scope = 'http://www.google.com/calendar/feeds/'
next_url = 'http://example.com/change/to/your/app'
secure = false  # set secure = true for signed AuthSub requests
sess = true
authsub_link = GData::Auth::AuthSub.get_url(next_url, scope, secure, sess)

上記のコードブロックは、authsub_link に次の URL を作成します。

https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F&session=1&secure=0

クライアント オブジェクトの authsub_url メソッドを使用することもできます。各サービスクラスにはデフォルトの authsub_scope 属性が設定されているため、独自の属性を指定する必要はありません。

client = GData::Client::DocList.new
next_url = 'http://example.com/change/to/your/app'
secure = false  # set secure = true for signed AuthSub requests
sess = true
domain = 'example.com'  # force users to login to a G Suite hosted domain
authsub_link = client.authsub_url(next_url, secure, sess, domain)

上記のコードブロックは、次の URL を作成します。

https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com%2Fchange%2Fto%2Fyour%2Fapp&scope=http%3A%2F%2Fdocs.google.com%2Ffeeds%2F&session=1&secure=0&hd=example.com

1 回限りのトークンをセッション トークンにアップグレードする

AuthSub は、データへのアクセス権を付与されると、http://example.com/change/to/your/app?token=SINGLE_USE_TOKEN にユーザーをリダイレクトします。この URL は、1 回限りのトークンをクエリ パラメータとして追加した next_url にすぎません。

次に、1 回限りのトークンを有効期間が長いセッション トークンと交換します。

client.authsub_token = params[:token] # extract the single-use token from the URL query params
session[:token] = client.auth_handler.upgrade()
client.authsub_token = session[:token] if session[:token]

セキュア AuthSub もよく似ています。唯一の追加方法は、トークンをアップグレードする前に秘密鍵を設定することです。

PRIVATE_KEY = '/path/to/private_key.pem'

client.authsub_token = params[:token]
client.authsub_private_key = PRIVATE_KEY
session[:token] = client.auth_handler.upgrade()
client.authsub_token = session[:token] if session[:token]

: セキュア トークンを使用するには、使い捨てトークンをリクエストするときに secure=true を設定してください。上記の AuthSubRequest URL の生成をご覧ください。

トークン管理

AuthSub には、トークンを管理するための 2 つのハンドラ AuthSubTokenInfoAuthSub お客様と TokenToken が用意されています。AuthSubTokenInfo は、トークンの有効性の確認に役立ちます。AuthSubRevokeToken は、データへのアクセスを切断するオプションをユーザーに提供します。ベスト プラクティスとして AuthSubRevokeToken を使用することをおすすめします。どちらの方法も Ruby ライブラリでサポートされています。

トークンのメタデータをクエリするには:

client.auth_handler.info

セッション トークンを取り消すには:

client.auth_handler.revoke

AuthSub の完全なスクープについて詳しくは、ウェブ アプリケーション用の AuthSub 認証のドキュメントをご覧ください。

OAuth

この記事を書いている時点では、OAuth は GData::Auth モジュールに追加されていません。

Rails の oauth-plugin または Ruby oauth gem を使用するときには、ユーティリティ ライブラリの OAuth の使用が比較的簡単です。いずれの場合も、GData::HTTP::Request オブジェクトを作成して、各ライブラリで生成された Authorization ヘッダーを渡すことをおすすめします。

フィードへのアクセス

GET(データの取得)

クライアント オブジェクトを設定したら、その get() メソッドを使用して、Google データフィードに対してクエリを実行します。XPath を使用して、特定の Atom 要素を取得できます。ユーザーの Google ドキュメントを取得する例を次に示します。

feed = client.get('http://docs.google.com/feeds/documents/private/full').to_xml

feed.elements.each('entry') do |entry|
  puts 'title: ' + entry.elements['title'].text
  puts 'type: ' + entry.elements['category'].attribute('label').value
  puts 'updated: ' + entry.elements['updated'].text
  puts 'id: ' + entry.elements['id'].text
  
  # Extract the href value from each <atom:link>
  links = {}
  entry.elements.each('link') do |link|
    links[link.attribute('rel').value] = link.attribute('href').value
  end
  puts links.to_s
end

POST(新しいデータの作成)

クライアントの post() メソッドを使用して、サーバーに新しいデータを作成します。次の例では、ID doc_id で共同編集者に new_writer@example.com を共同編集者として追加します。

# Return documents the authenticated user owns
feed = client.get('http://docs.google.com/feeds/documents/private/full/-/mine').to_xml
entry = feed.elements['entry']  # first <atom:entry>

acl_entry = <<-EOF
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl='http://schemas.google.com/acl/2007'>
  <category scheme='http://schemas.google.com/g/2005#kind'
    term='http://schemas.google.com/acl/2007#accessRule'/>
  <gAcl:role value='writer'/>
  <gAcl:scope type='user' value='new_writer@example.com'/>
</entry>
EOF

# Regex the document id out from the full <atom:id>.
# http://docs.google.com/feeds/documents/private/full/document%3Adfrk14g25fdsdwf -> document%3Adfrk14g25fdsdwf
doc_id = entry.elements['id'].text[/full\/(.*%3[aA].*)$/, 1]
response = client.post("http://docs.google.com/feeds/acl/private/full/#{doc_id}", acl_entry)

PUT(データの更新)

サーバー上のデータを更新するには、クライアントの put() メソッドを使用します。次の例では、ドキュメントのタイトルを更新します。ここでは、前のクエリのフィードがあることを前提としています。

entry = feed.elements['entry'] # first <atom:entry>

# Update the document's title
entry.elements['title'].text = 'Updated title'
entry.add_namespace('http://www.w3.org/2005/Atom')
entry.add_namespace('gd','http://schemas.google.com/g/2005')

edit_uri = entry.elements["link[@rel='edit']"].attributes['href']
response = client.put(edit_uri, entry.to_s)

削除

サーバーから <atom:entry> などのデータを削除するには、delete() メソッドを使用します。 次の例では、ドキュメントを削除します。このコードは、前のクエリのドキュメント エントリがあることを前提としています。

entry = feed.elements['entry'] # first <atom:entry>
edit_uri = entry.elements["link[@rel='edit']"].attributes['href']
client.headers['If-Match'] = entry.attribute('etag').value  # make sure we don't nuke another client's updates
client.delete(edit_uri)

新しい Rails アプリケーションを作成する

通常、新しい Rails アプリを作成する最初の演習では、スキャフォールド ジェネレータを実行して MVC ファイルを作成します。その後、rake db:migrate を実行してデータベース テーブルを設定します。ただし、アプリケーションでは Google Documents List API にデータのクエリを行うため、一般的なスキャフォールディングやデータベースは必要ありません。代わりに、新しいアプリケーションとシンプルなコントローラを作成します。

rails doclist
cd doclist
ruby script/generate controller doclist

config/environment.rb に次の変更を加えます。

config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
config.gem 'gdata', :lib => 'gdata'

最初の行は、アプリから ActiveRecord のフックを解除します。2 行目は、起動時に gdata gem を読み込みます。

最後に、DoclistController でデフォルト ルート(「/」)を documents アクションに接続することにしました。config/routes.rb に次の行を追加します。

map.root :controller => 'doclist', :action => 'all'

コントローラを起動する

スキャフォールディングが生成されなかったため、app/controllers/doclist_controller.rbDoclistController に「all」というアクションを手動で追加します。

class DoclistController < ApplicationController
  def all
    @foo = 'I pity the foo!'
  end
end

app/views/doclist/all.html.erb を作成します。

<%= @foo %>

ウェブサーバーを起動し、開発を開始する

ruby script/server を呼び出して、デフォルトのウェブサーバーを起動できるようになりました。問題がなければ、ブラウザで http://localhost:3000/ にカーソルを合わせると「I pity the foo!」と表示されます。

ヒント: public/index.html の削除または名前変更を忘れないでください。

処理が完了したら、最終的な DoclistControllerApplicationController を確認します。Google Contacts API の呼び出しを処理する ContactsController もご覧ください。

まとめ

Google Data Rails アプリの作成で一番難しいのは、Rails の構成です。もう一つは、アプリケーションのデプロイです。Apache には mod_rails を使用することを強くおすすめします。設定、インストール、実行もとても簡単です。すぐにご利用いただけます。

リソース

付録

DocList Manager は、この記事で説明したトピックを示す完全な Ruby on Rails サンプルです。完全なソースコードは、プロジェクト ホスティングから入手できます。