概要
Twitter Account Activity API を使うことでリプライの自動返信をできます。 しかし、手順が複雑であり公式ドキュメントも分かりにくいと感じたため記事にまとめます。
リプライの自動返信には以下の二段階が必要です。
- 認証を行いアプリケーションを Webhook に登録する
- Webhook からリプライイベント通知を受け取り返信を行う
本記事では、図のアプリケーションを実装します。
実装
このリポジトリに実装例があります。
1. 認証を行いアプリケーションを Webhook に登録する
Twitter API の利用申請
API 利用するために、登録します。 Twitter 側が承認を行い、登録に時間がかかります。 詳しい説明は省略します。
Twitter API の中でも、Account Activity API を利用します。
作成したアプリで Account Activity API を登録します。
Dev environment label
は後から使います。
詳しい説明は省略します。
Challenge-Response Checks と Webhook の登録
Account Activity API から Webhook イベント通知を受け取るアプリケーションをデプロイする必要があります。 そのアプリケーションがあなたが作ったものか確認するために、Challenge-Response Checks を行います。
具体的には、GET /crc_check?crc_token=hoge
のようなリクエストが飛んでくるので
{ "response_token": "sha256=correct_response_token" }
を正しく返す必要があります。
リクエスト先のエンドポイント(/crc_token
)はこちらで指定できます。
response_token
の生成には、CONSUMER_SECRET
が必要で認証になります。
また、HTTPS 通信ができるサーバーでないとエラーになります。
アプリケーションの実装
func HandlerCrcCheck(c *gin.Context) { // Requestを受ける req := GetCrcCheckRequest{} if err := c.Bind(&req); err != nil { c.JSON(http.StatusBadRequest, err) return } // CrcTokenを生成し、Responseに詰める mac := hmac.New(sha256.New, []byte(os.Getenv("CONSUMER_SECRET"))) mac.Write([]byte(req.CrcToken)) res := GetCrcCheckResponse{ Token: "sha256=" + base64.StdEncoding.EncodeToString(mac.Sum(nil)), } // Responseを返す c.JSON(http.StatusOK, res) } type GetCrcCheckRequest struct { CrcToken string `json:"crc_token" form:"crc_token" binding:"required"` } type GetCrcCheckResponse struct { Token string `json:"response_token"` }
Webhook を登録する
Insomnia を使ってリクエストを送信し、Webhook に登録します。
https://api.twitter.com/1.1/account_activity/all/<your-dev-environment-label>/webhooks.json?url=<your-crccheck-endpoint>
にリクエストを送信します。
<your-dev-environment-label>
は、最初に Account Activity API を登録する際に入力したものです。
<your-crccheck-endpoint>
は、Challenge-Response Checks を行うエンドポイントです。
なお、このエンドポイントは HTTPS でないと弾かれます。
{ "id": "1288888350132737027", "url": "https://98694ca5ac8e.ngrok.io/twitter_webhook", "valid": true, "created_timestamp": "2020-07-30 17:25:04 +0000" }
のようにid
がレスポンスとして帰ってくれば成功です。
次に、https://api.twitter.com/1.1/account_activity/all/<your-dev-environment-label>/subscriptions.json
にリクエストを送ります。
先ほどのように OAuth のヘッダーをセットし、それに加えてリクエストボディとして先ほどのid
を含む json を付与します。
204 が帰ってくれば成功です。 これでWebhookの登録は完了です。
Tips1
僕は最初、Insomnia での登録がなぜかうまくいきませんでした。 公式で Webhook 管理用のアプリケーションが提供されています。 上で行ったことはこちらでも可能です。 Webhook の登録解除もできます。
README にしたがってセットアップすることで、ローカルサーバーを立ち上げることができます。
Tips2
AWS 等のサーバーにデプロイしながら CRC チェックの部分をデバッグしていくのはとてもめんどくさいので、開発中は ngrok を使うことを推奨します。
これを利用することで、ローカルホストのサーバーを外部公開することができるので、効率よく Webhook の登録の確認を行うことができます。
$ ngrok http 3000 $ curl http://98694ca5ac8e.ngrok.io/twitter_webhook\?crc_token\=hoge {"response_token":"sha256=6kMzK/Hv5JCUiFwMzIJy8T+2N/uxhuSdn+GmTYb+Enc="}%
使い方は以下を参照してください。
2. Webhook からリクエストを受け取り、返信を行う
リプライイベント通知を受け取り、そのリクエストから情報を取得してリプライに対してリプライを返信します。 こちらは、Webhook からのリクエストを構造体にマッピングさえしてしまえば複雑ではないです。
func HandlerTwitterActivity(c *gin.Context) { // Requestを受ける req := PostTwitterActivityRequest{} if err := c.Bind(&req); err != nil { c.JSON(http.StatusBadRequest, err) return } // 略 // リプライを返す params := url.Values{} params.Set("in_reply_to_status_id", req.TweetCreateEvents[0].TweetIDStr) twitterApiClient := NewTwitterApiClient() status, err := twitterApiClient.PostTweet(fmt.Sprintf("@%s %s", req.TweetCreateEvents[0].User.ScreenName, content), params) if err != nil { c.JSON(http.StatusBadRequest, err) return } c.JSON(http.StatusOK, status) } type PostTwitterActivityRequest struct { UserID string `json:"for_user_id" form:"for_user_id" binding:"required"` TweetCreateEvents []TweetCreateEvent `json:"tweet_create_events" form:"tweet_create_events" binding:"required"` } type TweetCreateEvent struct { TweetIDStr string `json:"id_str" form:"id_str" binding:"required"` Text string `json:"text" form:"text" binding:"required"` User struct { IDStr string `json:"id_str" form:"id_str" binding:"required"` ScreenName string `json:"screen_name" form:"screen_name" binding:"required"` } `json:"user" form:"user" binding:"required"` }