Go言語でQiitaの人気記事のリンクをSlackに送信する

Blog Single

前回、QiitaのAPIで一週間分の人気記事を取得するというプログラムを作成したという記事を投稿しましたが、今回はそのプログラムを利用してSlackに通知させるプログラムを作成しました。

API Tokenの取得

Slack botのAPIトークンの取得は以下のページから行えます。

Slack botのAPIトークン

画面の右上でSlackのワークスペースを選択してbotの名前を入力してボタンを押すと、作成されます。

その後の画面で、APIトークンが表示されるので、保管しておきましょう。

プログラムの作成

以前の一週間分の人気記事を取得するプログラムから、前日だけの記事を取得するように変更して、チャンネルにメッセージを送るというプログラムを作成します。

Slackにメッセージを送るのは次のパッケージを用います。

GitHub – nlopes/slack: Slack API in Go

構成としては以下のようになります。

$ tree -L 2
.
├── qiita
│   └── qiita.go
└── send.go

1 directory, 2 files

以前作成したファイルをqiitaディレクトリに格納して、ファイルで指定するパッケージ名をqiitaに変えて、パッケージ化して他のフォルダからも呼び出せるようにしました。

qiita.go

package qiita

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "os"
    "time"
)

// jsonのパース用に構造体を定義
type Data struct {
    Url            string `json:"url"`
    Title          string `json:"title"`
    LikesCount     int    `json:"likes_count"`
    ReactionsCount int    `json:"reactions_count"`
    PageViewsCount int    `json:"page_views_count"`
}

// Qiitaからデータを取得
func FetchQiitaData(accessToken string, targetDate time.Time) []Data {

    baseUrl := "https://qiita.com/api/v2/"
    action := "items"

    // 1リクエストあたり最大30件取得
    baseParam := "?page=1&per_page=30"

    // monthだけintではなくMonth型のため型変換が必要
    year, month, day := targetDate.Date()
    targetDay := dateNum2String(year, int(month), day)

    year, month, day = targetDate.AddDate(0, 0, 1).Date()
    nextDay := dateNum2String(year, int(month), day)

    // 投稿の検索クエリを作成
    // 検索クエリ stocks:>NUM created:<YYYY-MM-DD created:>YYYY-MM-DD
    // 指定日に投稿されたストック数20以上の記事を取得
    varParam := "&query=stocks:>20+created:>=" + targetDay + "+created:<" + nextDay

    endpointURL, err := url.Parse(baseUrl + action + baseParam + varParam)
    if err != nil {
        panic(err)
    }

    b, err := json.Marshal(Data{})
    if err != nil {
        panic(err)
    }

    var resp = &http.Response{}
    // qiitaのアクセストークンがない場合はAuthorizationを付与しない
    if len(accessToken) > 0 {
        resp, err = http.DefaultClient.Do(&http.Request{
            URL:    endpointURL,
            Method: "GET",
            Header: http.Header{
                "Content-Type":  {"application/json"},
                "Authorization": {"Bearer " + accessToken},
            },
        })
    } else {
        resp, err = http.DefaultClient.Do(&http.Request{
            URL:    endpointURL,
            Method: "GET",
            Header: http.Header{
                "Content-Type": {"application/json"},
            },
        })
    }
    defer resp.Body.Close()

    if err != nil {
        panic(err)
    }

    b, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

    var datas []Data

    if err := json.Unmarshal(b, &datas); err != nil {
        fmt.Println("JSON Unmarshal error:", err)
        return nil
    }
    return datas
}

// データの出力
func QiitaData2String(datas []Data) string {

    result := ""

    for _, val := range datas {
        result += fmt.Sprintln(val.Title, "(", val.LikesCount, ")", "\n",val.Url)
    }

    return result
}

// 年月日の数値を文字列に変換
func dateNum2String(year int, month int, day int) string {
    return fmt.Sprintf("%d-%d-%d", year, month, day)
}

func FetchQiitaArticles(targetDate time.Time) string {

    // アクセストークン取得
    qiitaToken := os.Getenv("QIITA_TOKEN")


    data := FetchQiitaData(qiitaToken, targetDate)

    return QiitaData2String(data)
}

そして、このパッケージを利用して前日に投稿された人気記事の取得を行ない、nlopes/slack パッケージを用いてメッセージの送信を行うプログラムを作成します。

パッケージのインストール

$ go get -u github.com/nlopes/slack

今回は、generalのチャンネルに送るようなプログラムなので、複数人で利用しているワークスペースにbotを追加した場合は、プログラムを変更して送り先を変更しましょう。

package main

import (
    "fmt"
    "time"
    "os"

    "github.com/nlopes/slack"
    // 作成したパッケージをインポート
    "./qiita"
        )

func main() {

    baseDate := time.Now()

    // 一前の日付を取得
    targetDate := baseDate.AddDate(0, 0, -1)

    qiitaArticles := qiita.FetchQiitaArticles(targetDate)

    // 対象の日付から一週間分のデータを取得
    dateText :=  fmt.Sprintf("%d-%d-%d", targetDate.Year(), int(targetDate.Month()), targetDate.Day())

    slackToken := os.Getenv("SLACK_TOKEN")
    // slackのアクセストークンがない場合はエラー
    if !(len(slackToken) > 0) {
        fmt.Println("Please Set Slack Access Token.")
        os.Exit(1)
    }

    api := slack.New(slackToken)
    params := slack.PostMessageParameters{}
    attachment := slack.Attachment{
        Pretext: qiitaArticles,
    }

    message := fmt.Sprintf("%s 話題の記事",dateText)

    params.Attachments = []slack.Attachment{attachment}
    channelID, timestamp, err := api.PostMessage("general", message, params)
    if err != nil {
        fmt.Printf("%s\n", err)
        return
    }
    fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
}

実行

Qiitaのトークンと先ほど取得したのトークンを環境変数に設定している場合

$ go run main.go

環境変数に追加していない場合は、実行の際に指定します。

$ SLACK_TOKEN=YOUR-SLACK-TOKEN QIITA_TOKEN=YOUR-QIITA-TOKEN go run send.go 

実行結果

以下のように、generalに送信されました。

まとめ

今回は実行して取得してきたデータを用いてそのまま送信させるというシンプルな内容でした。
今回利用したパッケージにまだまだ機能がありそうなので、他の機能を使ってみたり、ソースコードを見てどう実装されているのかを見てみるのも面白いと思います。

参考

golang で始める Slack bot 開発 – at kaneshin

Posted by MatsumotoKazuki
PHPやJavaで開発を行っているエンジニア。 LOLというゲームの試合を観戦するのが好きです。

Other Posts: