Facebook Graph APIに、batch requestで複数のリクエストをまとめて投げる


[CFTraq.jp](http://cftraq.jp) の機能追加としてソーシャルシェア数を取るようにしようと思う。現在、日次でクロールしてる案件は500件弱あるので、まとめて投げないとひどいことになる。ということでbatch request。

公式情報は以下
https://developers.facebook.com/docs/graph-api/making-multiple-requests

- 50リクエストまで一つのバッチにまとめて投げられるとのこと。


# まずはCUIからcurlを使って試してみる

```batch.sh
curl -s 
	-F 'access_token=***access_token***' 
	-F 'batch=[
		{"method": "GET", "relative_url": "v2.3/?id=https://qiita.com/&fields=og_object{engagement},share"},
		{"method": "GET", "relative_url": "v2.3/?id=http://kobito.qiita.com/&fields=og_object{engagement},share"}
	]' 
	-F 'include_headers=false' 
	https://graph.facebook.com/ | jq '.'

# 実際には1行
curl -s -F 'access_token=***access_token***' -F 'batch=[{"method": "GET", "relative_url": "v2.3/?id=https://qiita.com/&fields=og_object{engagement},share"},{"method": "GET", "relative_url": "v2.3/?id=http://kobito.qiita.com/&fields=og_object{engagement},share"}]' -F 'include_headers=false' https://graph.facebook.com/ | jq "."

```

- curlに-sをつけて通信状況の表示を省略
- `-F 'batch=[{...}]'` の形式でバッチリクエストを記述
- 各リクエストは{}にJSONで記述。methodとrelative_urlは必須
- `&fields=og_object{engagement},share`を付けてるのは[ここ](http://blog.hello-world.jp.net/api/2221/)を参照。
- `-F 'include_headers=false'`をつけてGraph APIから返ってくる時のヘッダーを省略
- （おまけ）最後に`jq '.'`でレスポンスのJSONを可視化している

レスポンスはこんな感じ。

```response.json
[
  {
    "code": 200,
    "body": "{\"og_object\":{\"engagement\":{\"count\":629,\"social_sentence\":\"629 people like this.\"},\"id\":\"143935272446719\"},\"share\":{\"comment_count\":0,\"share_count\":629},\"id\":\"https:\\/\\/qiita.com\\/\"}"
  },
  {
    "code": 200,
    "body": "{\"og_object\":{\"engagement\":{\"count\":304,\"social_sentence\":\"304 people like this.\"},\"id\":\"10150590829744321\"},\"share\":{\"comment_count\":0,\"share_count\":304},\"id\":\"http:\\/\\/kobito.qiita.com\\/\"}"
  }
]
```


# koalaを使ってrubyから投げてみる
rubyからGraph APIを叩くには[koala](https://github.com/arsduo/koala)が便利。

```batch.rb
# Graph APIはv2.3を使用
Koala.config.api_version = "v2.3"

# 単一のリクエスト
graph = Koala::Facebook::API.new("***access_token***") 
graph.get_object("/", :id => "https://qiita.com/")

# バッチリクエスト
api = Koala::Facebook::API.new("***access_token***") 
results =  api.batch do |batch_api|
	batch_api.get_object("/", :id => "https://qiita.com/")
	batch_api.get_object("/", :id => "http://kobito.qiita.com/")
end
```

resultsの中身はこんな感じ。

```results.rb
results
 => [{"id"=>"https://qiita.com/", "shares"=>550}, {"id"=>"http://kobito.qiita.com/", "shares"=>303}]
```


# railsに組み込んでみる
koala wikiにちょうどrailsに使う際のやり方が載ってる。
https://github.com/arsduo/koala/wiki/Koala-on-Rails

```koala.rb
#config/initializers/koala.rb
Koala::Facebook::OAuth.class_eval do
  def initialize_with_default_settings(*args)
    raise "application id and/or secret are not specified in the envrionment" unless ENV['FB_APP_ID'] && ENV['FB_APP_SECRET']
    initialize_without_default_settings(ENV['FB_APP_ID'].to_s, ENV['FB_APP_SECRET'].to_s, args.first)
  end 

  alias_method_chain :initialize, :default_settings 
end

# Graph APIはv2.3を使用
Koala.config.api_version = "v2.3"
```

APP_IDとAPP_SECRETは環境変数で設定。

```.sh
export FB_APP_ID='***fb_app_id***'
export FB_APP_SECRET='***fb_app_secret***'

# herokuなら以下
heroku config:set FB_APP_ID='***fb_app_id***'
heroku config:set FB_APP_SECRET='***fb_app_secret***'
```

使い方は以下のような感じ。

```rails_koala.rb
urls = ["https://qiita.com/", "http://kobito.qiita.com/"]

graph = Koala::Facebook::API.new(Koala::Facebook::OAuth.new.get_app_access_token)

results =  graph.batch do |batch_api|
	urls.each { |url|
		batch_api.get_object("/", :id => url)
	}
end
```

resultsの中身はこんな感じ。

```.rb
results
 => [{"og_object"=>{"id"=>"143935272446719", "description"=>"Qiitaは、プログラマのための技術情報共有サービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 &amp; 公開することができます。", "title"=>"Qiita - プログラマの技術情報共有サービス", "type"=>"website", "updated_time"=>"2015-05-16T04:59:42+0000", "url"=>"https://qiita.com/"}, "share"=>{"comment_count"=>0, "share_count"=>630}, "id"=>"https://qiita.com/"}, {"og_object"=>{"id"=>"10150590829744321", "description"=>"エンジニアのためのMacアプリ「kobito」をQiitaが開発中!リリースまであと○○日…", "title"=>"Project ``kobito`` - ``kobito``先行利用ユーザー募集締切とニュースレター登録", "type"=>"website", "updated_time"=>"2015-05-11T11:24:27+0000", "url"=>"http://kobito.qiita.com/"}, "share"=>{"comment_count"=>0, "share_count"=>304}, "id"=>"http://kobito.qiita.com/"}]
```

Like数は`results[0]["share"]["share_count"]`とかでFixnumで取れる。