ZaimのAPIをRuby on RailsからOAuthを使って叩いてみる
普段は会計簿をつけているZaimというお気に入りのWebサービスがあるのだが、標準で用意されている分析がいまいち細かいところまで見れないので、自分でデータを取得してみることにした。
https://zaim.net
Zaimは開発者向けのAPIが提供されているようだが、OAuth 1.0aで認証されているので、Ruby on RailsのアプリケーションからZaimにOAuthで認証し、Zaimの家計簿データを取得して画面表示するところまでをやってみた。
今回の環境は以下。
- Mac OS X Yosemite 10.10.5
- Ruby 2.2.2
- Rails 4.2.3
Zaim APIからアプリケーションを登録する
まず、Zaim開発センターというページにて、アクセスするアプリケーションを登録する。
以下にログインし、「新しいアプリケーションを追加」をクリックする。
https://dev.zaim.net/
今回はRailsによるWebアプリなので、サービス種は「ブラウザアプリ」としておく。
また、サービスのURLは今回はlocalhostで起動するWebアプリを想定して、localhostのURLを指定しておく。
ちなみにポート番号は指定出来ないもよう(フォーマットエラーになる)。
※アプリケーション名は適当に変更すること
以下のような画面が出るので、Consumer KeyとConsumer Secretをメモしておく。これはOAuthでアクセスするときにアプリケーションを特定するために使う。
Ruby on RailsからZaim連携アプリケーション開発
今回はRuby on Railsの画面から、OAuthを使って以下の流れでZaimデータを取得する画面を作ってみる。
- アプリケーションにアクセスし、Zaim連携ボタンをクリックする
- Zaimに転送され、連携を許可する
- Zaimのデータを取得する
まず、RailsでOAuthを使うための’oauth’というgemをgemfileに追加し、bundle install
gem 'oauth'
続いて、Railsでビューとコントローラを作成する。
今回はDBにデータを保持しないので、モデルは作らない。
$ rails g controller zaimauth
コントローラを実装する。中身の詳細は後ほど。
(CONSUMER_KEYやCONSUMER_SECRETは環境変数に切り出すべきだが。。今回は分かりやすさのためクラス定数にしてしまう)。
require "json" require "oauth" class ZaimauthController < ApplicationController CONSUMER_KEY = '<メモしたConsumer Key>' CONSUMER_SECRET = '<メモしたConsumer Secret>' CALLBACK_URL = 'http://localhost/callback' API_URL = 'https://api.zaim.net/v2/' def top end def login set_consumer @request_token = @consumer.get_request_token(oauth_callback: CALLBACK_URL) session[:request_token] = @request_token.token session[:request_secret] = @request_token.secret redirect_to @request_token.authorize_url(:oauth_callback => CALLBACK_URL) end def callback if session[:request_token] && params[:oauth_verifier] set_consumer @oauth_verifier = params[:oauth_verifier] @request_token = OAuth::RequestToken.new(@consumer, session[:request_token], session[:request_secret]) access_token = @request_token.get_access_token(:oauth_verifier => @oauth_verifier) session[:access_token] = access_token.token session[:access_secret] = access_token.secret redirect_to money_path else logout end end def money set_consumer @access_token = OAuth::AccessToken.new(@consumer, session[:access_token], session[:access_secret]) money = @access_token.get("#{API_URL}home/money") @money = JSON.parse(money.body) end def logout session[:request_token] = nil session[:access_token] = nil redirect_to '/zaimauth' end private def set_consumer @consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, site: 'https://api.zaim.net', request_token_path: '/v2/auth/request', authorize_url: 'https://auth.zaim.net/users/auth', access_token_path: '/v2/auth/access') end end
ビューも簡単に実装してしまう。
- top.html.haml
%p= link_to 'login', login_path %p= link_to :logout
- money.html.haml
%p= @money
ルーティングも忘れずに。
- routes.rb
Rails.application.routes.draw do get 'top' => 'zaimauth#top' get 'callback' => 'zaimauth#callback' get 'login' => 'zaimauth#login' get 'money' => 'zaimauth#money' end
動作確認
さて、これで一通り動くものができたはず。画面を動かしながら、上で書いたコードを見る。
railsサーバ起動
Zaim APIにて、サービスのURLをポート番号なしでで設定しているため、
デフォルトの3000番ポートではなく、80番ポートで起動した。
普通にやるとエラーになったため、sudoをつけると回避できた。
$ sudo rails s -p 80
アプリケーションにアクセス
まずトップページを表示する。
http://localhost/top
topページは何もロジックはなく、loginリンクをクリックすると、http://localhost/login へ遷移する。
http://localhost/login
コントローラのloginメソッドは以下のような実装をしている。
def login set_consumer @request_token = @consumer.get_request_token(oauth_callback: CALLBACK_URL) session[:request_token] = @request_token.token session[:request_secret] = @request_token.secret redirect_to @request_token.authorize_url(:oauth_callback => CALLBACK_URL) end
set_consumerでコンシューマオブジェクトを初期化している。request_tokenは後から使う必要があるため、tokenとsecretの値をsessionに保持しておく。
redirect_to @request_token.authorize_url(:oauth_callback => CALLBACK_URL)とすることで、ZaimのOAuth認証画面へリダイレクトされる。このときにoauth_callbackにアプリケーションの戻りのパスを渡しておくと、Zaimで認証が通った後に、自動的にリダイレクトしていくれる。
loginリンクをクリックすると、以下のようにZaimにとばされるので、ログインする。
正常にログインできると、認証が完了のメッセージが表示され、少し待つとリダイレクトされる。
リダイレクト先のURLは以下を指定しておいたが、ZaimでOAuthの認証が成功すると、自動でこのURLにリダイレクトしてくれる。さらにこのとき、URLパラメータでoauth_verifierの値がいっしょに渡される。これはOAuthの認証を通過したユーザが、APIのアクセストークンを取得するときに必要となる文字列のため、callback先でsessionに保存しておく。
http://localhost/callback
def callback if session[:request_token] && params[:oauth_verifier] set_consumer @oauth_verifier = params[:oauth_verifier] @request_token = OAuth::RequestToken.new(@consumer, session[:request_token], session[:request_secret]) access_token = @request_token.get_access_token(:oauth_verifier => @oauth_verifier) session[:access_token] = access_token.token session[:access_secret] = access_token.secret redirect_to money_path else logout end end
@oauth_verifier = params[:oauth_verifier]はURLパラメータで渡されたoauth_verifierの値を切り出している。
その値を使ってrequest_tokenを取得し、そこからget_access_tokenでアクセストークンを取得している
アクセストークンの取得に成功すると、access_tokenとaccess_token_secretという二つの文字列が手に入るが、この二つを使うと以降APIにアクセスできる。そのため、この二つをsessionに保存しておく。
あとは通常の画面だとリクエストをする画面にでも飛ばせばよいが、今回はZaimの全データをこのまま取得してみる。
callbackからmoney_pathにリダイレクトしているが、moneyでは以下のロジックを実装している。
def money set_consumer @access_token = OAuth::AccessToken.new(@consumer, session[:access_token], session[:access_secret]) money = @access_token.get("#{API_URL}home/money") @money = JSON.parse(money.body) end
保存しておいたaccess_tokenとaccess_token_secretを使ってアクセストークンオブジェクトを再構築し、getメソッドからZaimのAPIにアクセスしている。
なお、ZaimのAPIの仕様は以下にまとまっている。
https://dev.zaim.net/home/api
今回、ビュー側では取得JSON形式のAPI問合せ結果をそのままま画面に表示している。
これで、Zaimに問合せたデータが正しく画面にまで受け取れていることが分かる!
まとめ
OAuthの仕組みを理解してしまえば、比較的簡単にZaimのデータを取得できることが分かった。Zaim API自体の情報はそれほど多くはなかったが、twitter APIなどにOAuthでアクセスするのとほとんど変わらないので、OAuth自体を勉強するいい機会になった。
あとはとったデータを好きに料理すればよい!また、データ登録用のAPIもあるので、自分のZaimクライアントを作ることもできそう!
以上