Google Cloud Functions で Twitter の定期投稿Botを作成

#はじめに
Twitterに定期的に投稿するBotを作ってみたのでその記録。
Twitter APIはGoogle Cloud Functions 上でnode.jsで実装。
スケジューリングは Google Cloud Schedulerを利用した。
Cloud Schedulerからは直接Cloud Functions を起動できないので、間にGoogle Cloud Pub/Sub を挟んでいる。

####ポイント
- Firebaseは利用しない（Firebaseが必須というような記事も見受けられるが誤解）
- TypeScriptも利用しない（Cloud Functionsが未対応なので使用しない）

#Twitter APIの準備
TwitterのAPIを利用するにはAPIのキーが必要だがこれはTwitter Developer Potalで取得する。
この辺りは、こちらあたりの記事が参考になるかと思う。
参考 [Twitter API を利用するには](https://qiita.com/taishi0202/items/092c267c0c6dc68347c5)

注意しなくてはいけないのが、TwitterのAPIは申請初期状態では"Essential access"モードとなっていて、Tweetを読むことはでるが、書き込む（Tweetをする）ことはできない。
Elevated access を申請すると、書き込みができるので、下記から申請が必要となる。
https://developer.twitter.com/en/portal/products/elevated
参考 [Twitter開発者ブログ - 新しい開発者プラットフォームでTwitterの未来を構築](https://blog.twitter.com/developer/ja_jp/topics/community/2021/build-whats-next-with-the-new-twitter-developer-platform)

また、OAuth1.0aを使用するので、Developer portalのアプリの User authentication settings からOAuth1.0aを使用可能としておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/7d962a41-c634-f825-1a5a-f09ce07697bc.png)

## APIの説明
今回はnode.jsを利用するので、APIのドキュメントは下記参照。
- Twitter API Node.js https://github.com/PLhery/node-twitter-api-v2
- 基本的な使い方 https://github.com/PLhery/node-twitter-api-v2/blob/master/doc/basics.md
- 認証周りの説明 https://github.com/PLhery/node-twitter-api-v2/blob/master/doc/auth.md

今回の様にユーザーに代わってTweetを行うときはUser-wide authenticationという認証フローが必要となる。
必要なキーは下記の4つ。
- Access Token
- Access Secret
- Client ID
- Client Secret
それぞれ、Twitter Developer PoratalのアプリのKeys and tokensから取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/06b1072e-2f4f-b9b3-ca6c-4930102f5fb6.png)


#Google Pub/Subの準備
Cloud Functionsは通常はHTTPリクエストをトリガーとするとが、Cloud Pub/Subをトリガーとすることもできる。
Pub/Subを使用できるように、あらかじめトピックを作っておく。
とりあえずトピックさえあればよいので、適当な名前で作ればよい。
サブスクリプションは、Cloud Functionで自動的に作成されるため、「デフォルトのサブスクリプションを追加する」のチェックは外しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/960e1c34-e560-7a7b-c4f3-3d09b7abc738.png)

#Google Cloud Functions のコーディング
Cloud FunctionsはPub/Subをトリガーとして起動するように作成する。
Cloud ConsoleでCloud Functionsを選択し、関数を作成する際「トリガーのタイプ」に"Cloud Pub/Sub"を選択し、事前に作成したトピックを選択すればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/d0f4a793-0691-763e-b0a9-01d12528d655.png)

Tweetするだけならソースは非常に簡単だ。
TwitterApiオブジェクトをインスタンス化する際に、事前に取得した4つのキーを与えれば認証することができる。
あとは、v1.tweet メソッドを呼び出すだけである。

```node.js:index.js
    const { TwitterApi } = require('twitter-api-v2');

    const client = new TwitterApi({
        appKey:'<Client ID>', 
        appSecret:'<Client Secret>', 
        accessToken:'<Access Token>', 
        accessSecret:'<Access Secret>'});

    exports.main = async (message, context) => {
        client.v1.tweet(<Tweet本文>);
    };
```

TwitterのAPIのドキュメントのサンプルはTypeScriptになっているが、Cloud FunctionsはTypeScript非対応となっている。
しかしながら、API自体はCommonJSに対応しているので、上記の様にrequire構文でインポートすれば使用可能。
なお、Pub/Subをトリガーとして関数は引数として二つの引数(messageとcontext)から渡される。
今回は使用してないがパブリッシュされたメッセージ本文はmessage引数から取得できる。詳しくは、下記ドキュメントを参照。
[Cloud Pub/Sub のチュートリアル](https://cloud.google.com/functions/docs/tutorials/pubsub)

package.jsonへTwitter APIへの依存関係の追記をお忘れなく。

```json:package.json
  "dependencies": {
    "twitter-api-v2": "^1.8.0"
  }
```
デプロイを実行すると、Cloud Functionが作成され、同時にCloud Pub/Subのサブスクリプションも自動的に作成される。
ここで、一度「関数のテスト」を実行して動作を確認しておく。

#Google Cloud Scheduler の設定
最後はスケジューラーを設定すれば完成。
スケジューラでCloud Pub/Subへ定期的にパブリッシュを行なえば、それをトリガーにCloud Functionsの関数が動くことになる。
設定自体は非常に簡単で、Cloud ConsoleでCloud Schedulerを表示し、Jobを作成するだけ。
まずは「スケジュールを定義」する
「頻度」の部分にcron形式でスケジュールを記述する。下の画像の例は毎時20時に実行する例。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/3189ba8e-e12b-be5c-5d03-9c86f1fdc576.png)
その他の例は下記ページあたりを参照
参照 [cron](https://qiita.com/kentmori-8/items/7d1279ca290ba7f586e7)

次に「実行内容を構成する」のところでターゲットタイプに「Pub/Sub」を選択し、事前に作成しておいたトピックを指定すればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635639/e0a25cea-c295-113f-6061-3eb69afc07a3.png)
メッセージ本文は使っていないのだが、必須項目なので何か適当な文字を入力しておく。

ジョブを作成後、「今すぐ実行」をクリックすればAPI経由でTweetされるはずである。