
今回は、C++とcurlでTwitter APIを使うときに僕の詰まったところを書いていこうかと思います。
ってのも、前にテキストデータを分析してみたよ~って記事を書きましたが、それと似たような感じで、Twitterのテキストデータを分析出来たらいいなぁ~って思って、最近はそのプログラムを作っていたんです。
で、そのときに色んな所に詰まりまくったんで、同じような現象で苦労してる人の助けになったらいいなぁ~ってことで、僕の苦労した問題と、その原因と解決方法をシェアしとこうかと思ったんです。
ちなみに、最終的にやりたいことは、Twitter上のテキストデータを分析することなので、主に「ツイートを取得する」ことしか書いていませんが、「ツイートする」とか「ダイレクトメールをどうこうする」みたいなときにも通用する話かとは思います。
この記事は一応、問題解決を目標にしてますが、基本的なことについても解説しているので、これからTwitter APIを動かすプログラムを書きたいって方にも役に立つ内容になってるかと思います。
ただし、Twitter APIの利用申請を終わらせていることを前提にしていますので、ご注意くださいませ~。
問題と原因と解決策
最初に僕の詰まったところを最初に言っておきますと、OAuth認証の所です。OAuth認証についての詳しい話はこちらをご覧いただければと思います~。
curlの設定を変えたり、署名作成に使うデータを変えてみたりしてたんですが、ずっと
"{"errors":[{"message":"Could not authenticate you","code":32}]}"
が返ってきてたんです。このエラーはOAuth認証に通らなかった場合に返ってくるエラーだそうで、署名が正常な値であるとサーバーに認められなかったときに返ってくるエラーだそうです。
ちなみに、OAuth認証を行うときに、Authorizationヘッダを送信する必要があるんですが、Authorizationヘッダがそもそも送信できていない場合は、別のエラー(code 215)が返ってきました。この場合は、HTTPリクエストの送信周りに問題がある可能性が高いのではないかと思いますので、その辺りを確認していただければと思います。
今回返ってきたエラーはcode 32だったので、Authorizationヘッダを送信できてはいるものの、その内容に問題があるということが分かります。
さて、結果から言いますと、僕の場合、code 32のエラーが返ってくる原因は、署名作成の部分とAuthorizationヘッダの部分にありました。
署名作成での間違い
まず、署名作成の方からです。僕の場合は、2つのミスがありました。一つは、署名作成に使うデータの間違いで、もう一つはURLエンコード忘れでした。
一応確認ですが、署名作成の流れは次のようになっています。
- 署名作成に使うキーを作る(&はエンコードしない)
- 署名作成に使うデータを作る(各要素をつなぐ&はエンコードしない)
- 実際に署名を作る
僕の場合はこの内、2番の「署名作成に使うデータを作る」に問題がありました。
署名作成に使うデータは、「リクエストメソッド&エンドポイント&パラメータ」という形をしていますが、問題があったのは、エンドポイントとパラメータの2か所でした。(説明の簡単化のために、「パラメータ」という単語を複数のパラメータをつないだものという意味で使っています。)
エンドポイントの間違い(というか、ただの勘違い)
まずは、エンドポイントの方からです。こちらの結論は、僕がずっと署名作成に使うデータを「リクエストメソッド&URL&パラメータ」の形だと勘違いしていたことが原因でした(トホホ)。
なので、この問題については素直に「リクエストメソッド&エンドポイント&パラメータ」の形に直すことが解決策だということになります。
エンドポイントってのは、Twitter APIの公式ドキュメントに書かれているResource URLの部分のことです。
HTTPリクエストを送るときに、エンドポイント(HTTPリクエストの送り先)の続きに「?オプション」という形で、何かしらのオプションを一緒に送信することが出来るようになっています。
例えば、「https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=Akito_Dataminer&count=10」みたいな感じで。このうちの?以降、つまり「screen_name=Akito_Dataminer&count=10」がオプションになっています。
で、署名作成に使うデータはこのうちの?以前の部分になります。つまり、この例で言えば、「https://api.twitter.com/1.1/statuses/user_timeline.json」の部分がエンドポイントということになります。
パラメータの間違い
次に、パラメータの話です。署名作成時に使うデータは「リクエストメソッド&エンドポイント&パラメータ」という形をしていることはすでに説明しました。
ただ、そのデータには注意点があって、リクエストメソッド、エンドポイント、パラメータの3つはURLエンコードをしておく必要があるんですが、それぞれをつないでいる&はエンコードしてはいけないということになっています。
要するに、パラメータの各要素はエンコードしないといけないけど、各要素をつなぐ&はエンコードしちゃダメってことですな。
なので、「パラメータ」もURLエンコードしなければいけないということになります。僕がミスしていたのはこの部分でした。
パラメータは、キーと値を=でつないで、それを&でつないだものということになっています。つまり、「キー=値&キー=値&・・・」という形になっているってことですな。
で、パラメータ全体はURLエンコードされている必要があるので、パラメータ内の&はURLエンコードされている必要があるということになります。
僕の場合は、この「パラメータ内の&のエンコード」を忘れてしまっていたことが、上手く動かない原因になっていました。
同じ&という文字であっても、各要素をつなぐ&はエンコードせず、パラメータ内の&はエンコードしなければならないという点にはお気を付けくださいませ~。
Authorizationヘッダでの間違い
次は、Authorizationヘッダを作るときに犯してしまっていた間違いについてです。
Authorizationヘッダは「Authorization: OAuth パラメータ名=値,パラメータ名=値,パラメータ名=値,・・・」という形になっています。上と「パラメータ」という言葉の定義がちょっと違うのでご注意ください。
ここで言う「パラメータ」とは、「oauth_consumer_key」とか「oauth_signature_method」とかのことです。
で、このときに注意がありまして、このAuthorizationヘッダですが、値の部分だけをURLエンコードしておかないといけないんです。
僕が引っ掛かったのはこの部分でして、値のURLエンコードを完全に忘れてしまっていました。そのせいで、署名作成に問題が無さそうで、Authorizationヘッダが送信できているにもかかわらず、OAuth認証が通らないみたいな現象が起きていました。
なので、Authorizationヘッダの値の部分だけをURLエンコードすることが解決策になりました。とはいえ、署名以外についてはURLエンコードしても変化が無いので、僕は署名の値だけをURLエンコードすることで対処しましたが。
まとめ
僕の場合は総じてURLエンコード忘れが原因でしたが、人によってはURLエンコードのし過ぎ(例えば、署名作成に使うデータで、各要素をつなぐ&までURLエンコードしちゃってたとか)みたいな感じで、code 32のエラーが返ってくる原因は他にも色々と考えられます。
なので、ここに書いた解決策だけ試せばオッケーという話にはなりませんが、Twitter APIのプログラムで同じような現象に悩んでいる方は、上に書いた辺りも確認してみてはいかがでしょうか?