mrjones氏のGoで実装したOAuthライブラリでTwitterAPIを利用するサンプルが公開されていますが、そのままではBotとして利用できないので、ソースを見ながらつぶやきとホームタイムラインが取得できるまでをやってみました。
最初に、ライブラリをインストールします。環境によっては先頭にsudoをつける必要があります。
go get github.com/mrjones/oauth
OAuthに必要なoauth.Consumerとoauth.AccessTokenを保持するstructと、その生成関数です。
package main
import (
"encoding/json"
"fmt"
"github.com/mrjones/oauth"
"io/ioutil"
"log"
)
type Twitter struct {
consumer *oauth.Consumer
accessToken *oauth.AccessToken
}
func NewTwitter(consumerKey, consumerSecret, accessToken, accessTokenSecret string) *Twitter {
twitter := new(Twitter)
twitter.consumer = oauth.NewConsumer(
consumerKey,
consumerSecret,
oauth.ServiceProvider{
RequestTokenUrl: "http://api.twitter.com/oauth/request_token",
AuthorizeTokenUrl: "https://api.twitter.com/oauth/authorize",
AccessTokenUrl: "https://api.twitter.com/oauth/access_token",
})
twitter.accessToken = &oauth.AccessToken{accessToken, accessTokenSecret}
return twitter
}
次に、GETとPOSTを行う関数です。関数の最初の行以外は同じコードになっています。
responseを取得し、ioutil.ReadAllで読み込んだ後、jsonデコードを行います。
戻り値として、なんでもあり?のinterface{}を返します。
func (t *Twitter) Get(url string, params map[string]string) (interface{}, error) {
response, err := t.consumer.Get(url, params, t.accessToken)
if err != nil {
return nil, err
}
defer response.Body.Close()
b, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
// decode
var result interface{}
err = json.Unmarshal(b, &result)
return result, err
}
func (t *Twitter) Post(url string, params map[string]string) (interface{}, error) {
response, err := t.consumer.Post(url, params, t.accessToken)
/* 以下Getと同じため省略 */
}
やっと、つぶやきます。NewTwitterの引数には各自値を入れて下さい。
twitter.Postの第1引数は、使用するAPIのURL Twitter APIを参照してください。
第2引数は、パラメータです。testとつぶやくので、keyにstatus、valueにtestとなっています。
func main() {
twitter := NewTwitter("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")
// testとつぶやく
res, err := twitter.Post(
"https://api.twitter.com/1.1/statuses/update.json", // Resource URL
map[string]string{"status": "test"}) // Parameters
if err != nil {
log.Fatal(err)
}
fmt.Println(res)
}
最後に、ホームタイムラインを取得します。今回はGet関数を使用します。
第2引数は、何も指定しないので空のmapにしています。
タイムラインの表示では、resをinterface{}の配列である[]interface{}に変換し、forでまわしています。forの中ではさらに、interface{}をmap[string]interface{}に変換した後、textを取り出して表示しています。
func main() {
twitter := NewTwitter("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")
res, err := twitter.Get(
"https://api.twitter.com/1.1/statuses/home_timeline.json", // Resource URL
map[string]string{}) // Parameters
if err != nil {
log.Fatal(err)
}
// タイムラインを表示
for _, val := range res.([]interface{}) {
tweet, _ := val.(map[string]interface{})
fmt.Println(tweet["text"])
}
}
JSONをdecodeするときに、あらかじめ定義したstructを渡せば、最後のinterface{}の面倒な処理はいらないのですが、APIごとに結果がことなる場合にそれぞれstructを作るのは大変なのでこのような処理にしました。
interfaceの使い方が間違っていたら、じゃんじゃんツッコミください。