at backyard

Color my life with the chaos of trouble.

公式のTwitter SDKをJavaScriptから触ってみたメモ(APIを用いたツイート編)

前回Twitter APIを用いてツイート取得やアカウントの取得について書いた。

shinshin86.hateblo.jp

今回はツイート編。

目次

長くなるので目次

Twitter API V2を用いてツイートをする

最近Twitter APIのv2を用いたツイートについて試していたがこれが結構個人的にはハマってしまい、ようやくプログラムから自動でツイートできるようになったというところ。

Twitter APIを用いてツイートした際の表示

本題に入る前に...
Twitter APIに関する開発者の間では常識かもしれないが、一応メモとしてTwitter API経由で呟いた場合、アプリ作成時に設定した名前がツイート上には表示される。

実際にツイートしたところのキャプチャ

上が実際にツイートしたところのキャプチャであり、下記がTwitter API側のダッシュボードのアプリ名のキャプチャ。
ここに設定した名前がツイートの際には記載される。

Twitter API側のダッシュボードのキャプチャ

Twitter API v2を用いてツイートをするまでに参考にしたところ。

下記のSDKを用いたが、こちらのexampleとして記載されているこのコードを大いに参考している。

github.com

他にも参考にできそうなところがあれば参考にしたいところだったが、参考になりそうなものを見つけることができなかった。
Twitter API V2はPostmanやGlitchアプリなどでのサンプルは用意されているのだが、コードレベルで認証部分も含めたコードというのが私が知る限りではなく、そういった意味でも少々苦労した。

コピペで貼ればTwitter API V2を用いてツイートできるコードがどこかにあればいいのに...もしご存じの方はコメントいただけると幸いです。

Twitter API V2を用いてツイートするサンプルコード

サンプルコードを実装する前に認証設定について紹介しておく。

Twitter APIの認証設定

Twitter APIdashboardから利用するアプリの User authentication settings を開き、下記のような設定にしておく必要がある。

OAuth 2.0を有効にしておく

Type of AppAutomated App or Bot にした。
(これはテストとして選択しているに過ぎないので、本来であれば利用用途にあったTypeを選択することになる)

なお選択するタイプによって必要となる認証方法が異なってくる
(詳細は公式ドキュメントを参照)

developer.twitter.com

例えば下記のようにSingle page appを選択している場合、認証時に client_secret は不要となる。

※下記はあとに貼るコードとなるが、この場合は実行するコードは下記のような形となる。

const authClient = new auth.OAuth2User({
  client_id: process.env.CLIENT_ID,
//  client_secret: process.env.CLIENT_SECRET, // ここが不要になる
  callback: "http://127.0.0.1:3000/callback",
  scopes: ["tweet.read", "tweet.write", "users.read", "offline.access"],
});

詳細な認証については必ず公式ドキュメントを参照し、適した認証方式を採用するように気をつける必要がある。

また、今回記載したコードはいろいろ試しながら書いたコードなので、必ずしも最低限の権限とはなっていない点に注意。
scopesとして指定されている offline.access も、このあと貼るコードのように一度の認証のみで済む内容であれば本来付ける必要はない。
上にも書いたが、ここについては実際に開発していく際は公式ドキュメントを参照した上で実装を進めていくのが良い。

Callback URLは http://127.0.0.1:3000/callback としている。
ちなみにWebsite URLはなんでもいいようなので、特に貼りたいサイトがなければ自分のTwitterのプロフィールページのURLとかでもOKそう。

サンプルコード

ここからは実装に移る。

今回もTypeScriptのSDKを用いている。
またOAuth2 認証の関係でExpressを用いている。

本当はCLIツールという体裁でツイートできるものを作りたかったが、ひとまずは愚直にサーバ上で諸々処理を行っていくスタイルで。
(というか、上のexampleを大いに参考にしているだけですが)

追記:CLI上でツイートまで完結できる(OAuth2の認証のみブラウザ)プログラムを書いたので貼っておく

shinshin86.hateblo.jp

まずは依存関係のインストール。

yarn add twitter-api-sdk express

次にコード。
ちなみにESMで書いています。(.mjs)

STATE など諸々の記述はサンプル用であることに注意。

import { Client, auth } from "twitter-api-sdk";
import express from "express";

const authClient = new auth.OAuth2User({
  client_id: process.env.CLIENT_ID,
  client_secret: process.env.CLIENT_SECRET,
  callback: "http://127.0.0.1:3000/callback",
  scopes: ["tweet.read", "tweet.write", "users.read", "offline.access"],
});

const app = express();

const client = new Client(authClient);

const STATE = "my-state";

app.get("/login", async function (req, res) {
  const authUrl = authClient.generateAuthURL({
    state: STATE,
    code_challenge_method: "s256",
  });
  res.redirect(authUrl);
});

app.get("/callback", async function (req, res) {
  try {
    const { code, state } = req.query;
    if (state !== STATE) return res.status(500).send("State isn't matching");

    await authClient.requestAccessToken(code);

    res.redirect("/post_tweet");
  } catch (error) {
    console.log(error);
  }
});

app.get('/post_tweet', async function (req, res) {
  try {
    const postTweet = await client.tweets.createTweet({
      // 呟く内容をここに記載
      text: "#TwitterAPI からのテスト投稿"
    });

    res.send(postTweet);
  } catch (error) {
    console.log('=== Tweet error ===');
    console.log(error);
  };
})

app.listen(3000, () => {
  console.log(`Go here to login: http://127.0.0.1:3000/login`);
});

これを tweet.mjsとかで保存して、あとは下記のように実行する。

CLIENT_ID=<取得したCLIENT ID> CLIENT_SECRET=<取得したCLIENT SECRET> node tweet.mjs

ツイッターにログインした状態で http://127.0.0.1:3000/login にアクセスすると下記のような画面になるので、アプリにアクセスを許可 を選択する。
(ログインしていなければ、ここでログインを促される)

認証が問題なければ client.tweets.createTweet が呼ばれてツイートされるといった具合です。

APIを触ってみた上でのメモ

scopesのタイポで時間が溶けた

最初 scopes 内でタイポしていた。

const authClient = new auth.OAuth2User({
  client_id: process.env.CLIENT_ID,
  client_secret: process.env.CLIENT_SECRET,
  callback: "http://127.0.0.1:3000/callback",
  scopes: ["tweet.read", "tweet.write", "user.read", "offline.access"], // 本当はusers.read
});

この状態でアプリを起動してログインしようとすると、下記のような画面になる。

最初別のところに原因があるのかと思い、Appの認証設定とかを見直しまくっていたが、ただのタイポだったというオチ。これで割と時間が溶けた。
というか、今振り返ればこれの調査で大半の時間を使っていたかも...

必要なscopesの調べ方

API V2ではscopes 内で利用したい権限を記載する。
当然ツイートを取得するだけの場合と、自分でツイートする場合では必要となるscopesも異なってくる。

ツイートをする際に必要になるscopesについては公式ドキュメントに記載されている。

POST /2/tweets | Docs | Twitter Developer Platform

上を見ると、ツイートを行うためには下記の3つのscopesが必要になることがわかる。

今回はこれらに加えて、offline.access も追加している形。
(でも今回の処理であればいらなかったかも)

scopesとログイン時の権限許可に関する文言について

scopesに応じて、ログイン時に許可を促される権限の文言が変わる。例えば上のようにscopesを、

と設定した場合、下記のようにログイン画面には表示される。

もし tweet.writeoffline.access のみにすると、

となる。

Twitter API上から同一文言のツイートはできない?

テストで同一内容のツイートを行ってみようとしたところエラーになった。

error: {
    detail: 'You are not allowed to create a Tweet with duplicate content.',
    type: 'about:blank',
    title: 'Forbidden',
    status: 403
  }

ツイート自体は重複でもできると思うし、重複したツイートは許可されていないと書かれているのでAPI側の設定次第でどうにかなるのかもしれない。

今回は以上となります。