(専用ライブラリなし)Twitter API v2でRubyからツイートするプログラムを書く

いよいよ４月末にせまったTwitterAPIのv1からv2への移行にむけて自作プログラムのAPIv1からv2への移行を行ったので備忘録としてかいておきます


# 前提情報

- APIリファレンス　https://developer.twitter.com/en/docs/twitter-api
- 各種言語のライブラリ https://developer.twitter.com/en/docs/twitter-api/tools-and-libraries/v2

# なぜTwitter v２用ライブラリを使わないのかの理由

- 大前提としてRubyの有名なライブラリである[twitter gem](https://github.com/sferik/twitter)はv1に対応してなさそうであること
- 公式サイトにのっている各種言語のライブラリはコミュニティライブラリがほとんどというためメンテナンスの信頼度にかけるのと、Rubyライブラリそのものの数が少なくコミットも去年だったりしたので今回は自前でAPI v2でツイートするコードを書くことにしました



# 公式のサンプルを見てみる

公式がサンプルコードをあげてくれていますのでまずそれを見てみます

https://github.com/twitterdev/Twitter-API-v2-sample-code
https://github.com/twitterdev/Twitter-API-v2-sample-code/blob/main/Manage-Tweets/create_tweet.rb

```ruby
require 'oauth'
require 'json'
require 'typhoeus'
require 'oauth/request_proxy/typhoeus_request'
require 'dotenv/load'
# The code below sets the consumer key and secret from your environment variables
# To set environment variables on Mac OS X, run the export command below from the terminal:
# export CONSUMER_KEY='YOUR-KEY', CONSUMER_SECRET='YOUR-SECRET'
consumer_key = ENV["CONSUMER_KEY"]
consumer_secret = ENV["CONSUMER_SECRET"]


create_tweet_url = "https://api.twitter.com/2/tweets"

# Be sure to add replace the text of the with the text you wish to Tweet.
# You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features.
@json_payload = {"text": "Hello world! TwitterAPI V2 ハローワールド"}

consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
	                                :site => 'https://api.twitter.com',
	                                :authorize_path => '/oauth/authenticate',
	                                :debug_output => false)

def get_request_token(consumer)

	request_token = consumer.get_request_token()

  return request_token
end

def get_user_authorization(request_token)
	puts "Follow this URL to have a user authorize your app: #{request_token.authorize_url()}"
	puts "Enter PIN: "
	pin = gets.strip

  return pin
end

def obtain_access_token(consumer, request_token, pin)
	token = request_token.token
	token_secret = request_token.secret
	hash = { :oauth_token => token, :oauth_token_secret => token_secret }
	request_token  = OAuth::RequestToken.from_hash(consumer, hash)

	# Get access token
	access_token = request_token.get_access_token({:oauth_verifier => pin})

    p access_token
    
	return access_token
end


def create_tweet(url, oauth_params)
	options = {
	    :method => :post,
	    headers: {
	     	"User-Agent": "v2CreateTweetRuby",
        "content-type": "application/json"
	    },
	    body: JSON.dump(@json_payload)
	}
	request = Typhoeus::Request.new(url, options)
	oauth_helper = OAuth::Client::Helper.new(request, oauth_params.merge(:request_uri => url))
	request.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
	response = request.run

	return response
end



# PIN-based OAuth flow - Step 1
request_token = get_request_token(consumer)
# PIN-based OAuth flow - Step 2
pin = get_user_authorization(request_token)
# PIN-based OAuth flow - Step 3
access_token = obtain_access_token(consumer, request_token, pin)

oauth_params = {:consumer => consumer, :token => access_token}


response = create_tweet(create_tweet_url, oauth_params)
puts response.code, JSON.pretty_generate(JSON.parse(response.body))
```

上記はサンプルコードにdotenvライブラリをたしているのと、メッセージに日本語をたしています
typhoeusというHTTPクライアントライブラリとoauthを使っているようです。
create_tweet_urlのURLはしっかりとv2になっているのでv2でツイートできるようですが、このプログラムはブラウザでURLを開いて認証してPINコードを打つということが必要で、バッチやBot的にツイートするというのには使えません。WEBアプリケーション連携するときのコードになります。

**ほしいのはこれじゃない**


## v1でBot作ってた人が欲しがるコードはこっち

サンプルコードを元に修正しました

```ruby
require 'oauth'
require 'json'
require 'typhoeus'
require 'oauth/request_proxy/typhoeus_request'
require 'dotenv/load'
# The code below sets the consumer key and secret from your environment variables
# To set environment variables on Mac OS X, run the export command below from the terminal:
# export CONSUMER_KEY='YOUR-KEY', CONSUMER_SECRET='YOUR-SECRET'
consumer_key = ENV["CONSUMER_KEY"]
consumer_secret = ENV["CONSUMER_SECRET"]
access_token = ENV["ACCESS_TOKEN"]
access_token_secret = ENV["ACCESS_TOKEN_SECRET"]

create_tweet_url = "https://api.twitter.com/2/tweets"

# Be sure to add replace the text of the with the text you wish to Tweet.
# You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features.
@json_payload = {"text": "Hello world! TwitterAPI V2 ハローワールド テスト。URLtest"}

def create_tweet(url, oauth_params)
	options = {
	    :method => :post,
	    headers: {
	     	"User-Agent": "v2CreateTweetRuby",
        "content-type": "application/json"
	    },
	    body: JSON.dump(@json_payload)
	}
	request = Typhoeus::Request.new(url, options)
	oauth_helper = OAuth::Client::Helper.new(request, oauth_params.merge(:request_uri => url))
	request.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
	response = request.run

	return response
end

# OAuth Consumerオブジェクトを作成
consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
	:site => 'https://api.twitter.com',
	:debug_output => false)

# OAuth Access Tokenオブジェクトを作成
access_token = OAuth::AccessToken.new(consumer, access_token, access_token_secret)

# OAuthパラメータをまとめたハッシュを作成
oauth_params = {
:consumer => consumer,
:token => access_token,
}

response = create_tweet(create_tweet_url, oauth_params)
puts response.code, JSON.pretty_generate(JSON.parse(response.body))
```


これでV2でツイートできます


## v1でBot作ってた人が欲しがるコードはこっち　　クラス版

```ruby
require 'oauth'
require 'json'
require 'typhoeus'
require 'oauth/request_proxy/typhoeus_request'
require 'dotenv/load'

class TwitterV2
  def self.tweet(text)
    # The code below sets the consumer key and secret from your environment variables
    # To set environment variables on Mac OS X, run the export command below from the terminal:
    # export CONSUMER_KEY='YOUR-KEY', CONSUMER_SECRET='YOUR-SECRET'
    consumer_key = ENV["CONSUMER_KEY"]
    consumer_secret = ENV["CONSUMER_SECRET"]
    access_token = ENV["ACCESS_TOKEN"]
    access_token_secret = ENV["ACCESS_TOKEN_SECRET"]

    create_tweet_url = "https://api.twitter.com/2/tweets"

    # Be sure to add replace the text of the with the text you wish to Tweet.
    # You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features.
    json_payload = {"text": text}

    def self.create_tweet(url, oauth_params, json_payload)
      options = {
        :method => :post,
        headers: {
          "User-Agent": "v2CreateTweetRuby",
          "content-type": "application/json"
        },
        body: JSON.dump(json_payload)
      }
      request = Typhoeus::Request.new(url, options)
      oauth_helper = OAuth::Client::Helper.new(request, oauth_params.merge(:request_uri => url))
      request.options[:headers].merge!({"Authorization" => oauth_helper.header}) # Signs the request
      response = request.run

      return response
    end

    # OAuth Consumerオブジェクトを作成
    consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
      :site => 'https://api.twitter.com',
      :debug_output => false)

    # OAuth Access Tokenオブジェクトを作成
    access_token = OAuth::AccessToken.new(consumer, access_token, access_token_secret)

    # OAuthパラメータをまとめたハッシュを作成
    oauth_params = {
      :consumer => consumer,
      :token => access_token,
    }

    response = create_tweet(create_tweet_url, oauth_params, json_payload)
    response
  end
end

```


```ruby
TwitterV2.tweet("あいうえお")
```


# API v2所感

APIリファレンスを見るとv2のみでメディアファイル添付つきのツイートは難しそうな感じでした。
mediaIDをツイートする感じですがmediaIDそのものを生成するには結局v1が今は必要そうなのでメディアアップロード機能がv2にできない限り今後プログラムからあげるのは難しいんじゃないかなと思いました。誰かできる手段を見つけたらお教えください