C#でTweetinviパッケージを使って、WindowsフォームアプリケーションからTwitterAPIを叩いてみた。

# 目次
- はじめに
- 使用環境
- APIとは？
- TwitterAPIの取得
- アプリの概要・機能
- 「Consumer API Keys」、「アクセストークン情報」を使った認証
- TweetinviAPIパッケージを使ってTwitterからUserオブジェクトやTweet、画像等の取得
- 参考動画
- 終わりに


# はじめに
現在(2021/4/26~2021/10/25)職業訓練校にてゲーム・Webアプリ開発を学んでおり、授業の一環でC#のWindowsフォームアプリケーション用いてアプリケーションの課題制作を行うということでしたので、普段利用しているTwitterの外部アプリケーションである『TweetDeck』を模したクライアントアプリケーションを作成しようと思い、取り組んでみましたが、思いの外ややこしくエラーが絶えなかった（それでいて、調べてみるとほとんど海外のドキュメントしか無くてかなり苦労しました。。）ので、自分と同じように悩まれた方の参考になればという事で、備忘録がてらまとめさせて頂きました。



# 使用環境
アプリの作成にあたり、統合開発環境はVisual Studio 2019を使用し、Windowsフォームアプリケーション(.NET Framework)を選択した上で、プロジェクトを作成しました。のちに詳しく説明しますが、Twitterからの情報の取得には、NuGetパッケージマネージャーからTweetinviAPI(4.0.2)をインストールしました。

- [Windowsフォームアプリケーションの作成方法はこちら。](https://docs.microsoft.com/ja-jp/visualstudio/ide/create-csharp-winform-visual-studio?view=vs-2019)

# APIとは？
まずはじめに、APIについて簡単に説明だけ入れておこうと思います。自分も初めてAPIを調べた時に、なんか曖昧な説明でよくわからなかったのを覚えています。

とにかくなんかよくわからないですが、度々目にするAPI。せっかく読んでいただいたので、この記事でざっくりでも良いので理解していってください。

簡単に言うと、API(Application Programming Interface)とは<font color="Blue">アプリと会話する為のルール</font>です。よく、「規約」という言葉で説明している記事を見かけるかと思います。自分もこの「規約」という言葉を目にして、「何のこっちゃ？？」状態になりました。「APIは、システム同士が会話する上での窓口的な役割を持つ」というところまでは何となく理解できたのですが、「で、なんで使うの？」というように、当時血まなこになって調べていた僕みたいに疑問を持つ方もいらっしゃるかもしれません。色々記事を読んだ中で一番しっくりきたのが以下の説明でした。

#### APIとは、<font color="Red">あるアプリから他のサービスorアプリの機能を使いたい時に使う</font>もの。

今回でいうと、作成したWindowsフォームアプリケーション(クライアントアプリケーション)から、TwitterAPIを利用してTwitter(リソースサーバー)のツイート・画像投稿機能や投稿一覧の取得、ユーザーの情報を取得したりするということになります。

通常なら、ユーザーがTwitterのアプリに対して、投稿一覧を読み込む(GETリクエスト)、ツイートを投稿する（POSTリクエスト）などの何かしらのリクエストをTwitterに対しておくり、その結果が返ってくる（レスポンス）という流れになるかとおもいます。今回はこれを、アプリケーション内部のプログラムからTwitterに対してリクエストを送って、そのレスポンスをアプリケーションのプログラム内部で受け取るという形になります。

# TwitterAPIの取得
恐らく、最初の大きな壁になるのはここだと思います。僕も過去にTwitterbotを作ろうとして、TwitterAPIの取得を試みましたが、TwitterAPI登録に失敗して諦めました（ここが本当にわかりにくい。。）

まず、[Twitter Developerのページ（開発者向けAPI提供サイト）](https://developer.twitter.com/)にアクセスします。アクセスしてみるとわかると思いますが、とにかく全部英語なので、どこをどういじったら良いのか最初は全くわかりませんでした（汗；）

ここの開発者専用サイトでまずは、自身のTwitterアカウントを申請して承認されないとTwitterAPIを利用する事ができません。また、この申請が非常に厄介でして、アプリケーションを作成する目的などのいくつかの項目を英語で100~200文字程度（もしくはそれ以下）で簡潔に述べなければいけません。実際僕も最初に申請したTwitterアカウントでは、適切なアカウントだとみなされずに承認に失敗しました。うまくいった時のポイントとしては、調べてみると参考になる英訳文章の例などがいくつかあったので、それをコピペして貼り付けるのと、Google翻訳などでオリジナルの文章などを作成して織り交ぜてみるとうまくいったので確実性は高いかと思います。参考にさせて頂いたサイトが分かり易かったのでご参照下さい。

- [Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ](https://qiita.com/kngsym2018/items/2524d21455aac111cdee)
- [例文参考サイト](https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/)

無事に自身のTwitterアカウントの承認に成功すれば、開発者専用サイト上でアプリケーションを作成します。（<font color="Red">Create an app</font>というボタンを押してください）

TwitterAPIを取得するためのアプリケーションを開発者専用サイト上で作成できたら、ようやくTwitterAPIを使う為に必要な以下の4つの情報を取得できます！

①<font color="Blue">コンシューマーキー(API key)</font>
②<font color="Blue">コンシューマーシークレット(API secret key)</font>
③<font color="Blue">アクセストークン(Access token)</font>
④<font color="Blue">アクセストークンシークレット(Access token secret)</font>

この4つの情報は忘れずに必ずどこかにメモして残しておいて下さい。（プログラムを書く際にたびたび使いますので）

もし忘れてしまった場合は何度でも再発行することが可能なので、再発行をしてきちんとメモを残すようにしておきましょう。

### <font color="Red">※注意点</font>(追記)
Twitterの開発者専用サイトで作成したアプリはデフォルトでは権限がRead onlyになっていますので、必ずSettingsのApp permissionsから権限を変更しておくのを忘れないようお気をつけ下さい！（自分もこれを知らなかったせいで投稿が反映されない状態で丸一日潰しました。）


# アプリの概要・機能
今回はTwitter(リソースサーバー)からデータを取得・更新をする簡単なサンプルフォームアプリケーションになります。

概要としては、フォームアプリを起動すると一つ目のフォーム(Form1.cs)が起動します。基本的な機能操作はこのフォーム上から行います。Form1上のフォロワーボタンを押すと二つ目のフォーム(Followers.cs)が起動します。このフォームはフォロワー情報を表示のみをするフォームになります

機能としては、

①ユーザー情報を取得して、フォームアプリケ上にアカウント画像、プロフィール名、ユーザー名、フォロワー数を表示
②文章の投稿、投稿時刻の表示
③フォロワーのプロフィール名・プロフィール画像を取得して一覧サイトを表示

実際これらの簡単な機能を実装するだけでかなりの時間を使いました。。

# 「Consumer API Keys」、「アクセストークン情報」を使った認証
まずは、一つ目のフォーム(Form1.cs)のソースコードを以下に記載します。これをもとに解説していきます。

```c#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Tweetinvi;
using Tweetinvi.Models;

namespace TwitterAPI_app
{
    //API Key →　wwwww
    //API Secret Key  →　xxxxx
    //Access Token　→　yyyyy
    //Access Token Secret　→　zzzzz

    public partial class FormTwitterPost : Form
    {
        //Twitter認証用セッション変数
        private string api_key = "wwwww"; 
        private string api_secret_key = "xxxxx";
        private string access_token = "yyyyy";
        private string access_token_secret = "zzzzz";

        
        //コンストラクタ
        public FormTwitterPost()
        {
            InitializeComponent();
            //「Consumer API Keys」、「アクセストークン情報」を使った認証
            Auth.SetUserCredentials(api_key, api_secret_key, access_token, access_token_secret);
        }

        private void FormTwitterPost_Load(object sender, EventArgs e)
        {
            //フォームを読み込んだ時の認証処理
            var user = User.GetAuthenticatedUser(); //ユーザーの取得
            var getTweets = Timeline.GetUserTimeline(user, 10);　//ツイートを取得
            var followers = User.GetFollowers(user.ScreenName); //フォロワーの取得

            profilePic.ImageLocation = user.ProfileImageUrl; //プロフィール画像を取得
            lblName.Text = user.Name;                        //プロフィール名の取得
            lblHander.Text = "@" + user.ScreenName;          //ユーザー名の取得


            //フォロワーの総数を表示させる
            displayFollowers.Text = "View Followers! (" + followers.Count() + ")";

            //取得したツイートを順番に表示させる処理
            foreach(var tweet in getTweets)
            {
                txtTweets.AppendText("-->" + tweet.FullText + " - " + tweet.TweetLocalCreationDate + Environment.NewLine + "__TWEET END__" + Environment.NewLine);
            }
            
        }
        

        //ツイートボタンをクリックしたときの処理
        private  void butTweet_Click(object sender, EventArgs e)
        {
            
            if (lblImage.Text != "")
            {
                byte[] file = File.ReadAllBytes(imgAttach.ImageLocation);
                //Tweet.PublishTweetWithImage(txtTweet.Text, file);
            }
            else
            {
                Tweet.PublishTweet(txtTweet.Text); //タイムラインにツイートを投稿
            }

            MessageBox.Show("ツイートを送信しました");

        }

        private void attachImage_Click(object sender, EventArgs e)
        {
            //画像をPictureBox、画像のパスをLabelに反映させる

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.ShowDialog();
            imgAttach.ImageLocation = ofd.FileName;
            lblImage.Text = ofd.FileName;
        }

        private void displayFollowers_Click(object sender, EventArgs e)
        {
            //フォロワーボタンをクリックした時にフォローフォームを呼び出す
            Followers showFollowers = new Followers();
            showFollowers.Show();
        }
    }
}

```





まずはコンストラクタの上の部分で変数宣言をして、認証に必要な４つの情報をそれぞれ代入しておきます。

次にNuGetパッケージの管理画面からTweetinviAPI(バージョン: 4.0.2)をダウンロードしました。後述しますが、このバージョンでないとエラーが出てしまうので、Visual Studio 2019をお使いの方は同じバージョンでインストールされる事をおすすめします。


インストールが完了すると、パッケージAPIの関連メソッドを利用する事ができ、<font color="Green">Auth.SetUserCredentials</font>メソッドを使って認証を完了させました。(このとき、PINコード入力は不要で、フォームを読み込むとすでに認証が完了していて、ようやくTwitterアカウントとの情報のやり取りをする事ができます。)

認証に関しては今回はパッケージのオブジェクトとして含まれていたAuth認証を使いましたが、認証に関しての理解を深めるのに一役買ってくれた記事を以下に載せておきました。

- [一番分かりやすい OAuth の説明](https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be)

#TweetinviAPIパッケージを使ってTwitterからユーザーオブジェクトやツイート、画像等の取得
認証が無事完了しましたので、晴れてTwitterと相互に情報の受け渡しができるようになります。が、ここで大きなエラーに出くわしました。

フォームを読み込んだときに認証は成功しているのに、何度読み込んでもユーザーオブジェクトが返ってこない（var userがnull）。。

正直調べ尽くしてもヒットするのが海外のドキュメントしかなかったので骨が折れる作業でした。このエラーには三日間程頭を悩まされ職業訓練校での課題制作中に他の方は自分の課題(8割の方はオリジナルゲームを作成していました)に夢中で取り組んでいる中、自分だけコードを書きたくても全く手が動かないという中々の地獄を体験しました。

調べている中で見つけた、海外の方が書いたとあるスタックオーバーフローの記事に書いてあった内容によりますと、Visual StudioのバージョンとTweetinviAPIパッケージのバージョンの不一致でユーザーオブジェクトがnullを返すエラーがよく起こるとの事でした。とりあえずTweetinviAPIパッケージのバージョンを古いものから順にインストールし直して実行していくと、(4.0.2)のバージョンでようやくユーザーオブジェクトが返ってきて無事に情報の受け渡しができるようになりました（嬉しくて教室で声が漏れました）。

ただ、参考動画にあった投稿と画像を一緒に投稿するというところだけ、パッケージのバージョンの違いからか取得できたTweetオブジェクト関連の便利メソッド<font color="Green">Tweet.PublishTweetWithImage(txtTweet.Text, file);</font>がオブジェクトブラウザーになく実行できなくてエラーになったので、コメントアウトにしています。

そして、フォロワーを表示しているボタンをクリックするとフォロワー一覧を表示するフォームが起動します。以下に二つ目のフォーム(Followers.cs)のソースコードを載せておきました。

```c#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Tweetinvi;

namespace TwitterAPI_app
{
    public partial class Followers : Form
    {
        //Twitter認証用セッション変数(sampleAPI_app)
        private string api_key = "wwwww";
        private string api_secret_key = "xxxxx";
        private string access_token = "yyyyy";
        private string access_token_secret = "zzzzz";

        public Followers()
        {
            //認証処理
            InitializeComponent();
            Auth.SetUserCredentials(api_key, api_secret_key, access_token, access_token_secret);
        }

        private void Followers_Load(object sender, EventArgs e)
        {
            var user = User.GetAuthenticatedUser();                 //ユーザーの取得
            var getFollowers = User.GetFollowers(user.ScreenName);  //フォロワーオブジェクトの取得


            foreach(var tweetieBird in getFollowers)
            {
                PictureBox profilePic = new PictureBox(); //PictureBoxインスタンス生成
                Label getFollowerName = new Label();      //Labelインスタンス生成

                //FlowLayoutPanelに画像を追加する処理
                flowLayoutPanel1.Controls.Add(profilePic);
                flowLayoutPanel1.Controls.Add(getFollowerName);

                getFollowerName.Text = tweetieBird.ScreenName;
                getFollowerName.ForeColor = Color.Blue;

                //プロフィール画像のレイアウトを調整
                profilePic.Width = 60;
                profilePic.Height = 60;
                profilePic.SizeMode = PictureBoxSizeMode.StretchImage;
                profilePic.BorderStyle = BorderStyle.FixedSingle;

                //フォロワーのプロフィール画像を表示する処理
                profilePic.ImageLocation = tweetieBird.ProfileImageUrl;
            }
        }
    }
}

```

# 参考動画
今回作成するにあたって参考にしたYouTubeの動画を以下に載せておきました。基本的にはボタンやテキストボックス、ピクチャーボックス、ラベルなどの位置はほとんど同じなのでこちらを見ていただくとわかりやすいかと思います。

①[認証・ユーザー情報の取得・投稿機能の実装](https://www.youtube.com/watch?v=PDZ0qts1jhI&list=PLDAJihEoxESfqYFqDqa8g5h4eKMtyi3pv&index=5&t=568s)
②[画像投稿機能の実装](https://www.youtube.com/watch?v=1RDnWuiBzTU&list=PLDAJihEoxESfqYFqDqa8g5h4eKMtyi3pv&index=6)
③[投稿の取得・表示機能の実装](https://www.youtube.com/watch?v=LwrXZ5xD3C8&list=PLDAJihEoxESfqYFqDqa8g5h4eKMtyi3pv&index=7)
④[フォロワーの取得・一覧をフォームに表示する機能の実装](https://www.youtube.com/watch?v=roR-oxVoO20&list=PLDAJihEoxESfqYFqDqa8g5h4eKMtyi3pv&index=8)


# 終わりに
今回TwitterAPIと大格闘しましたおかげで多少なりとAPIに関して理解が深まったのは大きな収穫です。コードの部分等でわかりにくい部分や誤っている部分などがございましたらコメントを頂けますと助かります。一応ソースコードも載せておきます。

https://github.com/yuuu1654/TwitterAPI_app/tree/master