OAuth gemだけでTwitter APIを使ってみる
Twitter gemは非常に優秀ですので、低レイヤーなOAuth gemを使ってTwitter APIにアクセスする必要はまずありません。
ただし、「Twitterからの応答をちゃんと返してくれているのだろうか?」と疑問があったときに、gemを介さずに直接アクセスする手段を知っておくことは大切なことだと思います。*1。
要約をQiitaに載せました
APIエンドポイント
REST API v1.1 Resources | Twitter Developers
で確認してください。
必要なもの
$ gem install oauth
しておきます。
ライブラリとして
require 'json' require 'oauth'
が必要です。
なおTwitter APIの返答がJSONなのでライブラリを入れています。
例を挙げておきます(もちろんニセモノ)。
consumer_key = '9Gu1FiE1IfKi32bR8Fw' consumer_secret = 'QUnRDVcl5FNCZ9C1j80OAjUJlguMNVyqbdrOrnjtQ' access_token = '2194235326-sm2SUkVRHMJ1CdwYG1f04klQMlxc4i05tkSbnZa' access_token_secret = 'oairK8FMvLZ8dqEVrCgh2brhyL0SCd5wpdkIoNxz62Jdi'
取得方法はtwitter OAuthのアクセストークンを取得 - 別館 子子子子子子(ねこのここねこ)を参考にしてください。
consumer key/secretの認証
consumer = OAuth::Consumer.new( consumer_key, consumer_secret, site:'https://api.twitter.com/' ) => #<OAuth::Consumer:0x007fa234d15410 @key="9Gu1FiE1IfKi32bR8Fw", @options= {:signature_method=>"HMAC-SHA1", :request_token_path=>"/oauth/request_token", :authorize_path=>"/oauth/authorize", :access_token_path=>"/oauth/access_token", :proxy=>nil, :scheme=>:header, :http_method=>:post, :oauth_version=>"1.0", :site=>"https://api.twitter.com/"}, @secret="QUnRDVcl5FNCZ9C1j80OAjUJlguMNVyqbdrOrnjtQ">
consumerインスタンスとaccess token/secretを使ってAPIアクセスするためのインスタンスを作る
endpoint = OAuth::AccessToken.new(consumer, access_token, access_token_secret) => #<OAuth::AccessToken:0x007fa234dfad30 @consumer= #<OAuth::Consumer:0x007fa234d15410 @http=#<Net::HTTP api.twitter.com:443 open=false>, @key="9Gu1FiE1IfKi32bR8Fw", @options= {:signature_method=>"HMAC-SHA1", :request_token_path=>"/oauth/request_token", :authorize_path=>"/oauth/authorize", :access_token_path=>"/oauth/access_token", :proxy=>nil, :scheme=>:header, :http_method=>:post, :oauth_version=>"1.0", :site=>"https://api.twitter.com/"}, @secret="QUnRDVcl5FNCZ9C1j80OAjUJlguMNVyqbdrOrnjtQ", @uri=#<URI::HTTPS:0x007fa234d63228 URL:https://api.twitter.com/>>, @params={}, @secret="oairK8FMvLZ8dqEVrCgh2brhyL0SCd5wpdkIoNxz62Jdi", @token="2194235326-sm2SUkVRHMJ1CdwYG1f04klQMlxc4i05tkSbnZa">
GETの例:@twitterapiのツイート履歴を見る
GET statuses/user_timeline | Twitter Developers
に載っている例です。APIのエンドポイントURLは次の通りです。
GET https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2
アカウント名がtwitterapiのツイートを2つ取得する、ということです。パラメータに関しては上のリンクから確認してください。
アクセスする
response = endpoint.request(:get, 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2') => #<Net::HTTPOK 200 OK readbody=true>
なお、 endpoint.request(:get, URL) と書きましたが、 endpoint.get(URL) で良いようです(このほうが読みやすい)。
返答の内容を確認
返答はNet::HTTPOKクラスのオブジェクトですのでresponse.bodyでbodyが取得できます。JSONなのでJSON.parse(response.body)で戻せます。
result = JSON.parse(response.body) => [{"created_at"=>"Wed May 21 18:29:30 +0000 2014", "id"=>469183215714828288, "id_str"=>"469183215714828288", "text"=> "RT @TwitterDev: Developer Spotlight: Botanicalls via @jbulava https://t.co/ "source"=>"web", "truncated"=>false, "in_reply_to_status_id"=>nil, "in_reply_to_status_id_str"=>nil, "in_reply_to_user_id"=>nil, "in_reply_to_user_id_str"=>nil, "in_reply_to_screen_name"=>nil, "user"=> {"id"=>6253282, "id_str"=>"6253282", "name"=>"Twitter API", "screen_name"=>"twitterapi", "location"=>"San Francisco, CA", "description"=> "The Real Twitter API. I tweet about API changes, service issues and happil "url"=>"http://t.co/78pYTvWfJd", "entities"=> {"url"=> {"urls"=> [{"url"=>"http://t.co/78pYTvWfJd", "expanded_url"=>"http://dev.twitter.com", "display_url"=>"dev.twitter.com", "indices"=>[0, 22]}]}, "description"=>{"urls"=>[]}}, "protected"=>false, "followers_count"=>2173311, "friends_count"=>48, "listed_count"=>12689, "created_at"=>"Wed May 23 06:01:13 +0000 2007", "favourites_count"=>26, "utc_offset"=>-25200, "time_zone"=>"Pacific Time (US & Canada)", "geo_enabled"=>true, "verified"=>true, "statuses_count"=>3504, "lang"=>"en", "contributors_enabled"=>false, "is_translator"=>false, "is_translation_enabled"=>false, "profile_background_color"=>"C0DEED", "profile_background_image_url"=> "http://pbs.twimg.com/profile_background_images/656927849/miyt9dpjz77sc0w3d "profile_background_image_url_https"=> "https://pbs.twimg.com/profile_background_images/656927849/miyt9dpjz77sc0w3 "profile_background_tile"=>true, "profile_image_url"=> "http://pbs.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_normal "profile_image_url_https"=> "https://pbs.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_norma "profile_banner_url"=> "https://pbs.twimg.com/profile_banners/6253282/1347394302", "profile_link_color"=>"0084B4", "profile_sidebar_border_color"=>"C0DEED", "profile_sidebar_fill_color"=>"DDEEF6", "profile_text_color"=>"333333", "profile_use_background_image"=>true, "default_profile"=>false, "default_profile_image"=>false, "following"=>false, "follow_request_sent"=>false, "notifications"=>false}, "geo"=>nil, "coordinates"=>nil, "place"=>nil, "contributors"=>nil, "retweeted_status"=> {"created_at"=>"Wed May 21 18:29:05 +0000 2014", "id"=>469183110723031041, "id_str"=>"469183110723031041", "text"=> "Developer Spotlight: Botanicalls via @jbulava https://t.co/EtJEF3XFOt", "source"=> "<a href=\"http://twitter.com/tweetbutton\" rel=\"nofollow\">Tweet Button</ "truncated"=>false, "in_reply_to_status_id"=>nil, "in_reply_to_status_id_str"=>nil, "in_reply_to_user_id"=>nil, "in_reply_to_user_id_str"=>nil, "in_reply_to_screen_name"=>nil, "user"=> {"id"=>2244994945, "id_str"=>"2244994945", "name"=>"TwitterDev", "screen_name"=>"TwitterDev", "location"=>"Internet", "description"=> "Developers and Platform Relations @Twitter. We are developer advocates. "url"=>"https://t.co/66w26cd6ZO", "entities"=> {"url"=> {"urls"=> [{"url"=>"https://t.co/66w26cd6ZO", "expanded_url"=>"https://dev.twitter.com/", "display_url"=>"dev.twitter.com", "indices"=>[0, 23]}]}, "description"=>{"urls"=>[]}}, "protected"=>false, "followers_count"=>5789, "friends_count"=>1177, "listed_count"=>99, "created_at"=>"Sat Dec 14 04:35:55 +0000 2013", "favourites_count"=>116, "utc_offset"=>-25200, "time_zone"=>"Pacific Time (US & Canada)", "geo_enabled"=>false, "verified"=>true, "statuses_count"=>374, "lang"=>"en", "contributors_enabled"=>false, "is_translator"=>false, "is_translation_enabled"=>false, "profile_background_color"=>"FFFFFF", "profile_background_image_url"=> "http://abs.twimg.com/images/themes/theme1/bg.png", "profile_background_image_url_https"=> "https://abs.twimg.com/images/themes/theme1/bg.png", "profile_background_tile"=>false, "profile_image_url"=> "http://pbs.twimg.com/profile_images/431949550836662272/A6Ck-0Gx_normal.p "profile_image_url_https"=> "https://pbs.twimg.com/profile_images/431949550836662272/A6Ck-0Gx_normal. "profile_banner_url"=> "https://pbs.twimg.com/profile_banners/2244994945/1396995246", "profile_link_color"=>"0084B4", "profile_sidebar_border_color"=>"FFFFFF", "profile_sidebar_fill_color"=>"DDEEF6", "profile_text_color"=>"333333", "profile_use_background_image"=>false, "default_profile"=>false, "default_profile_image"=>false, "following"=>false, "follow_request_sent"=>false, "notifications"=>false}, "geo"=>nil, "coordinates"=>nil, "place"=>nil, "contributors"=>nil, "retweet_count"=>12, "favorite_count"=>10, "entities"=> {"hashtags"=>[], "symbols"=>[], "urls"=> [{"url"=>"https://t.co/EtJEF3XFOt", "expanded_url"=> "https://blog.twitter.com/2014/developer-spotlight-botanicalls", "display_url"=>"blog.twitter.com/2014/developer…", "indices"=>[47, 70]}], "user_mentions"=> [{"screen_name"=>"jbulava", "name"=>"Jon Bulava", "id"=>987121, "id_str"=>"987121", "indices"=>[37, 45]}]}, "favorited"=>false, "retweeted"=>false, "possibly_sensitive"=>false, "lang"=>"en"}, "retweet_count"=>12, "favorite_count"=>0, "entities"=> {"hashtags"=>[], "symbols"=>[], "urls"=> [{"url"=>"https://t.co/EtJEF3XFOt", "expanded_url"=> "https://blog.twitter.com/2014/developer-spotlight-botanicalls", "display_url"=>"blog.twitter.com/2014/developer…", "indices"=>[63, 86]}], "user_mentions"=> [{"screen_name"=>"TwitterDev", "name"=>"TwitterDev", "id"=>2244994945, "id_str"=>"2244994945", "indices"=>[3, 14]}, {"screen_name"=>"jbulava", "name"=>"Jon Bulava", "id"=>987121, "id_str"=>"987121", "indices"=>[53, 61]}]}, "favorited"=>false, "retweeted"=>false, "possibly_sensitive"=>false, "lang"=>"en"}, {"created_at"=>"Fri May 16 17:13:22 +0000 2014", "id"=>467352118966235136, "id_str"=>"467352118966235136", "text"=> "Forthcoming tweak to streaming API error codes from June https://t.co/HbQsmb "source"=> "<a href=\"http://itunes.apple.com/us/app/twitter/id409789998?mt=12\" rel=\"n "truncated"=>false, "in_reply_to_status_id"=>nil, "in_reply_to_status_id_str"=>nil, "in_reply_to_user_id"=>nil, "in_reply_to_user_id_str"=>nil, "in_reply_to_screen_name"=>nil, "user"=> {"id"=>6253282, "id_str"=>"6253282", "name"=>"Twitter API", "screen_name"=>"twitterapi", "location"=>"San Francisco, CA", "description"=> "The Real Twitter API. I tweet about API changes, service issues and happil "url"=>"http://t.co/78pYTvWfJd", "entities"=> {"url"=> {"urls"=> [{"url"=>"http://t.co/78pYTvWfJd", "expanded_url"=>"http://dev.twitter.com", "display_url"=>"dev.twitter.com", "indices"=>[0, 22]}]}, "description"=>{"urls"=>[]}}, "protected"=>false, "followers_count"=>2173311, "friends_count"=>48, "listed_count"=>12689, "created_at"=>"Wed May 23 06:01:13 +0000 2007", "favourites_count"=>26, "utc_offset"=>-25200, "time_zone"=>"Pacific Time (US & Canada)", "geo_enabled"=>true, "verified"=>true, "statuses_count"=>3504, "lang"=>"en", "contributors_enabled"=>false, "is_translator"=>false, "is_translation_enabled"=>false, "profile_background_color"=>"C0DEED", "profile_background_image_url"=> "http://pbs.twimg.com/profile_background_images/656927849/miyt9dpjz77sc0w3d "profile_background_image_url_https"=> "https://pbs.twimg.com/profile_background_images/656927849/miyt9dpjz77sc0w3 "profile_background_tile"=>true, "profile_image_url"=> "http://pbs.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_normal "profile_image_url_https"=> "https://pbs.twimg.com/profile_images/2284174872/7df3h38zabcvjylnyfe3_norma "profile_banner_url"=> "https://pbs.twimg.com/profile_banners/6253282/1347394302", "profile_link_color"=>"0084B4", "profile_sidebar_border_color"=>"C0DEED", "profile_sidebar_fill_color"=>"DDEEF6", "profile_text_color"=>"333333", "profile_use_background_image"=>true, "default_profile"=>false, "default_profile_image"=>false, "following"=>false, "follow_request_sent"=>false, "notifications"=>false}, "geo"=>nil, "coordinates"=>nil, "place"=>nil, "contributors"=>nil, "retweet_count"=>34, "favorite_count"=>38, "entities"=> {"hashtags"=>[], "symbols"=>[], "urls"=> [{"url"=>"https://t.co/HbQsmbkLmQ", "expanded_url"=>"https://dev.twitter.com/discussions/28457", "display_url"=>"dev.twitter.com/discussions/28…", "indices"=>[57, 80]}], "user_mentions"=>[]}, "favorited"=>false, "retweeted"=>false, "possibly_sensitive"=>false, "lang"=>"en"}]
POSTの例:ツイートする
POST statuses/update | Twitter Developers
に載っている例です。APIのエンドポイントURLは
POST https://api.twitter.com/1.1/statuses/update.json
で、ツイートする内容は
POST Data status=Maybe%20he%27ll%20finally%20find%20his%20keys.%20%23peterfalk
とありますが、どちらかといえば日本語が使えるか気になりますので
tweet messageには 日本語が使えます。
という文をツイートしてみましょう。
アクセスする
ツイート文はPOSTデータに入れるのですが、以下のようにハッシュで渡します。
response = endpoint.request(:post, 'https://api.twitter.com/1.1/statuses/update.json', status: 'tweet messageには 日本語が使えます。') => #<Net::HTTPOK 200 OK readbody=true>
endpoint.get(URL) と同様にこちらも endpoint.post(URL, hash) と書いたほうが読みやすいですね。
返答の内容を確認
result = JSON.parse(response.body) => {"created_at"=>"Thu May 22 11:11:28 +0000 2014", "id"=>4694353711895674xx, "id_str"=>"4694353711895674xx", "text"=>"tweet messageには 日本語が使えます。", (以下略)
まとめ
require 'json' require 'oauth' consumer_key = '9Gu1FiE1IfKi32bR8Fw' consumer_secret = 'QUnRDVcl5FNCZ9C1j80OAjUJlguMNVyqbdrOrnjtQ' access_token = '2194235326-sm2SUkVRHMJ1CdwYG1f04klQMlxc4i05tkSbnZa' access_token_secret = 'oairK8FMvLZ8dqEVrCgh2brhyL0SCd5wpdkIoNxz62Jdi' consumer = OAuth::Consumer.new( consumer_key, consumer_secret, site:'https://api.twitter.com/' ) endpoint = OAuth::AccessToken.new(consumer, access_token, access_token_secret) # GET response = endpoint.request(:get, <API_ENDPOINT_URL>) result = JSON.parse(response.body) # POST response = endpoint.request(:post, <API_ENDPOINT_URL>, {<PARAMETER_HASH>}) result = JSON.parse(response.body)
OAuth::Consumer#requestメソッドを使った例
すこし使いづらいのですが、こちらのやりかたを先に見つけたので、メモしておきます。
上のやり方ではOAuth::AccessToken#initialize*2を作ってから取り扱っている
Method: OAuth::ConsumerToken#initialize ― Documentation for oauth (0.4.7)
のですが、この例ではconsumerインスタンスを直接扱います。
Method: OAuth::Consumer#request ― Documentation for oauth (0.4.7)
念のためにconsumerインスタンスを再掲しておきます。
consumer = OAuth::Consumer.new( consumer_key, consumer_secret, site:'https://api.twitter.com/' )
GET
access_token_pair = OAuth::Token.new(access_token, access_token_secret) response = consumer.request(:get, <API_ENDPOINT_URL>, access_token_pair) result = JSON.parse(response.body)
POST
response = consumer.request(:post, <API_ENDPOINT_URL>, access_token_pair, {}, {<PARAMETER_HASH>}) result = JSON.parse(response.body)
なお、POSTの際には引数の空ハッシュ({})が必要です。
Method: OAuth::Consumer#request ― Documentation for oauth (0.4.7)
参考
OAuth gemでのアクセス方法に関してTwitter公式の記事を参考にしました。