morito

個人的に勉強したことのメモを投稿していく技術ブログ。最近はWebアプリ開発と量子コンピュータの勉強をしてます。

TwitterAPI使って自動でTweetするGoのプログラムを作る with Docker

前回の続きです

今回はTwitterAPIを使ってGoで書かれたプログラムからツイートしてみます



環境

  • Docker Version 20.10.2
  • docker-compose version 1.27.4, build 40524192



前準備

Twitterのアカウントを取得して以下の4つを発行します



ソースコード

TwitterAPIを有効にするためOAuth認証を通します

keys.go

package keys

import 
(
    //Twitter APIに必要なimportになります。なければインストールしましょう。   
    "github.com/ChimeraCoder/anaconda"
    "os"
)

func GetTwitterApi() *anaconda.TwitterApi {
    anaconda.SetConsumerKey(os.Getenv("TFC_API_KEY"))
    anaconda.SetConsumerSecret(os.Getenv("TFC_API_SECRET_KEY"))
    api := anaconda.NewTwitterApi(os.Getenv("TFC_ACCESS_TOKEN"), os.Getenv("TFC_ACCESS_SECRET"))
    return api
}

ツイートするための
main.go

package main

import (
    "fmt"
    . "fmt"
    "local.packages/keys" // go modulus環境でローカルパッケージをインポート
)

func main() {
    api := keys.GetTwitterApi()

    tweet_text := fmt.Sprintf("テストツイート")

    tweet, err := api.PostTweet(tweet_text, nil)
    if err != nil {
        panic(err)
    }
    Print(tweet.Text)
 
    fmt.Println("posting!")
}

importでローカルにあるkeysパッケージをもってくるのですがこの書き方がベストプラクティスかどうかは微妙です。

この記事を参考にしています

mainパッケージとkeysパッケージ両方にgo.modを配置してmainのほうのgo.modファイルをこうします↓

module main.go

go 1.14

replace local.packages/keys => ./keys // modules名を相対パスに置き換えている

require (
    // ry
)

なんでこれでうまくいってるのかよくわかってないです

ディレクトリ構成はこうなります↓ keysパッケージのほうのmodファイルには何も書いてません

> tree
.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── go.mod
├── go.sum
├── keys
│   ├── go.mod
│   └── keys.go
├── main.go



Dockerfileを修正

Dockerfileにアナコンダをとってくる文を追加します

FROM golang:1.14.0-alpine3.11

# ビルド時にashを使う
SHELL ["/bin/ash", "-c"]
WORKDIR /go/src/app
COPY ./ ./

# Go Modulesを使うと明言する
ENV GO111MODULE=on

# apkはalpine linux(超軽量なLinux)の独自のパッケージ管理システム
RUN apk add --no-cache alpine-sdk

# Golang 環境構築
# (追加)TwitterAPIを捌くのにアナコンダを使用します
RUN go get github.com/ChimeraCoder/anaconda 



環境変数受け渡しのためにdocker-compose.ymlを修正

安全にトークンとAPIキーを持ってくるために書き加えます

ホスト(コンテナの外)のシェルに環境変数をセット

私はFishシェラーをなのでset -x環境変数をセットします
TFCは今回のプロジェクトの名前なので気にしないでください

set -x TFC_ACCESS_TOKEN xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
set -x TFC_ACCESS_SECRET xxxxxxxxxxxxxxxxxxxxxxxxxxxx
set -x TFC_API_KEY xxxxxxxxxxxxxxxxxxxxx
set -x TFC_API_SECRET_KEY xxxxxxxxxxxxxxxxxxxxx
docker-composeでコンテナ起動時に環境変数を設定するようにする

こちらの記事を参考にして .ymlファイルを書きました。↓

version: '3' # composeファイルのバーション指定
services:
  app: # service名
    build: . # ビルドに使用するDockerfileがあるディレクトリ指定
    tty: true # コンテナの起動永続化
    volumes:
      - .:/go/src/app # マウントディレクトリ指定
    environment: 
      TFC_API_KEY: ${TFC_API_KEY?err} # composeが起動しているシェルの環境変数を利用
      TFC_API_SECRET_KEY: ${TFC_API_SECRET_KEY?err} # 未設定またはempty値の場合にエラ〜メッセージを表示して終了する
      TFC_ACCESS_TOKEN: ${TFC_ACCESS_TOKEN?err}
      TFC_ACCESS_SECRET: ${TFC_ACCESS_SECRET?err}
コンテナの中に入って環境変数を確認
$ docker-compose up -d
$ docker-compose exec app /bin/ash
$ set

省略

setコマンドで先ほどセットしたKEYやTOKENが表示されたら成功です



ツイートしてみる

コンテナの中に入ってgo runします

> docker-compose exec app /bin/sh
/go/src/app # go run main.go 
テストツイートposting!

自分のツイッターアカウントを見にいってみたら成功してました

ちなみに2連続で同じ内容を呟くと以下のようなエラーが返ってきました

panic: Get https://api.twitter.com/1.1/statuses/update.json returned status 403, {"errors":[{"code":187,"message":"Status is a duplicate."}]}

おつかれさまです。次回はツイートの取得をやります。



参考サイト

案外知られてないdocker-composeの環境変数定義の記法

Go Modules でインターネット上のレポジトリにはないローカルパッケージを import する方法

TwitterはGoでゴー。