TypeScriptで型安全にツイートする

はじめに
プログラムから動的にツイートする方法を紹介します。
自動ツイートの一翼を担う部分なので、色々応用できると自動化が捗るかもしれません。
今回は、数あるツイッタークライアントの中でもおすすめな、
twitter-api-v2
を中心に説明します。
Twitter Client の選定
まず、Client ライブラリを使用するのか否かという判断ですが、個人的には使用すべきだと思います。
公式のサンプルを見てみましょう。
curl -XPOST
--url 'https://api.twitter.com/1.1/statuses/update.json?status=hello'
--header 'authorization: OAuth
oauth_consumer_key="oauth_customer_key",
oauth_nonce="generated_oauth_nonce",
oauth_signature="generated_oauth_signature",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="generated_timestamp",
oauth_token="oauth_token",
oauth_version="1.0"'プログラムからツイートするためには、 oauth_signature を計算する必要があります。
oauth_signature は、signature base string と signing key を HMAC-SHA1
でハッシュ化する必要があります。
この作業はあまり本質的ではないので、コードベースのサイズがシビアでない限りは、再開発を避け素直にライブラリを使うべきでしょう。
さて、Node.js で利用可能な Twitter Client ライブラリは多くあります。
基本的には Declaretion file が提供されているので、 TypeScript
で問題なく使うことができます。 なので、なんでも良いとも言えますが、 ツイート
をプログラムからするという用途であれば、twitter-api-v2 をおすすめします。
最も有名な Client ライブラリは
twitterだと思いますが、それと比較してtwitter-api-v2
は以下の3つの特徴があります。
- パッケージサイズが小さい
- 強い型付け
- Promise ベース
それぞれ簡単に見ていきましょう。
パッケージサイズが小さい
twitter クライアントよりも、パッケージサイズが 15 分の 1 程度になっています。
Twitter Client
はサーバーサイドで使用されるため、パッケージサイズに関してはそこまでシビアになることはありません。
ただサーバーレス環境ではコンテナなどのイメージサイズなどに影響しますし、インストールの時間によりワークフローの速度にも影響があるため、小さいに越したことはありません。
twitter-api-v2 は依存パッケージがないため、かなりサイズを削減できています。
強い型付け
すべての Twitter クライアントライブラリは基本的には、エンドポイントへのリクエストのラッパーです。
ライブラリにより AOuth
ヘッダーの作成の手間から開放されます。ただ、そのほとんどでレスポンス型は any
などの弱い型になっています。 これには理由があります。twitter-api-v2
以外のライブラリでは、HTTP
クライアントの薄いラッパーを目指して実装されています。
例えば、次のエンドポイントへのリクエストをtwitter
クライアントを使うと以下のようになります。
https://api.twitter.com/1.1/statuses/update.json
import Twitter from "twitter";
import type { ResponseData } from "twitter";
import type { Response } from "request";
const client = new Twitter(credentials);
client.post(
"statuses/update",
{
status: "tweet content",
},
(error, responseData, response) => {
error; // any
resonseData; // ResponseData
response; // Response
},
);レスポンスはコールバック関数によって取得できます。これは後述する Promise
ベースに対する特徴になっています。
レスポンスのコールバック関数を見てみると、第一引数は any 型となっています。
また、第2引数は ResponseData という型が返ってきます。この実態は次の型です。
interface ResponseData {
[key: string]: any;
}また、第 3 引数は request の
Response 型が返ってきます。このことから、 twitter は http リクエストに
request を使っていることが推定できます。
残念ながら、この3つの引数は型安全とは言えません。
一方、 twitter-api-v2 を使った場合は次のようになります。
import Twitter, { TweetV1 } from "twitter-api-v2";
const client = new Twitter(credentials);
const result = await client.v1.tweet("tweet content");
result; // TweetV1twitter-api-v2 は ツイートや
ユーザー情報、メディア情報のための専用のインターフェイスがあるため、
強い型付けにより安全にレスポンスの処理ができます。
単にツイートしたいだけなら、エラー処理はあまり厳密でなくてもいいかもしれませんが、 型安全に越したことはないですよね。
Promise ベース
すでに例示しているように twitter-api-v2 は Promise
オブジェクトを戻り値とします。 Promise
であることの優位点は今更述べる必要はないと思いますが、可読性の高い記述ができます。
以上のように Node.jsを使ってツイートするなら、twitter-api-v2
がよりベターなことがわかるかと思います。
ツイートする
さて、実際にツイートしてみましょう。なお、Twitter developer platformへの登録は済んでいる前提で解説します。
まずは、Twitter の Developer Portal から、プロジェクトを作成し API Key を生成します。

Customer Keys から
- API Key
- API Secret Key
が、
Authentication Tokens から
- Access Token
- Access Token Secret
が取得できます。 このとき、Authentication Tokens のパーミッションに注意が必要です。
パーミッションは次の 3 種類あります。
- Read only
- Read and write
- Read, write and access Direct Messages
トークンをツイートに用いる場合、パーミッションは Read and Write
以上でなくてはなりません。 Read only
だった場合は、権限を変更した上で、トークンの再生成が必要です。
さて 4 つの値が取得できたらあとは簡単です。
まず、 twitter-api-v2 をインストールします。
npm i -D twitter-api-v2コンストラクタに 4 つの値を与えます。インターフェイスのキーの名称が若干異なります。
| Developer Portal | Constractor |
| API Key | appKey |
| API Secret Key | appSecret |
| Access Token | accessToken |
| Access Token Secret | accessSecret |
import Twitter from "twitter-api-v2";
const client = new Twitter({
appKey,
appSecret,
accessToken,
accessSecret,
});
client.v1.tweet("test");これでツイートができたかと思います。できない場合は、パーミッションを見直してみるといいかもしれません。
エラー処理
基本的は上の例で問題ありませんが、エラーが発生するパターンが存在します。 ツイートの重複とレートリミットです。
エラーの場合は、そのどちらも 403 エラーが発生します。
ツイートの重複
ツイート内容は最近のツイートと比較され、重複があった場合にエラーが発生します。
ここで重要なのは、最直近のツイートのみが比較されるわけではないということです。 最新のツイートと比較的近い期間に行ったツイートが比較され、同じ内容をツイートできないような仕様になっているようです。
レートリミット
3 時間で 300 件以下しかツイートは行えません。これにはリツイートも含むので、プログラムからリツイートしている場合は、上限に注意が必要です。
どちらのエラーも Promise の reject メソッドが呼ばれます。
なので、通常のエラー処理のようにtry-catch で補足するか、Promise の catch
メソッドで補足できます。