Slackからメッセージ取得してShinyで表示してみる


R言語のWebアプリ作成フレームワークShinyを使って、外部のWebAPIにアクセスするときのTipsです。
いろんなAPIと連携できるとRとShinyの表現力がより活かせますね。

今回はSlackからメッセージ履歴を取得してみます。

# Slack側の準備

WebAPIを利用する場合、大体利用するシステム側でこういった準備が必要かと。不要な場合もありますが。

## トークン取得

slack APIのページからトークン取得を行います。
レガシーなやつと新しいやつがありますが、今回はとりあえずレガシーなほうで。

- [Legacy tokens](https://api.slack.com/custom-integrations/legacy-tokens)

こちらはAPIにアクセスするときに必要になるのでメモしておきましょう。

## チャンネルIDの取得

指定のチャンネルのメッセージをとってくる場合、チャンネル名指定ではダメで、チャンネルIDが必要になります。
このIDがどこから取得していいかわかりにくいかったので、簡単な方法をメモ。
Web版のslackに移行し、該当ちゃんねるを開くと、URLにIDが出てきます。

![image](https://qiita-image-store.s3.amazonaws.com/0/83530/6db59039-f45d-ff03-e239-a0dd57cf5f91.png)

## エンドポイントの確認

利用したいアクションごとにURLが用意されているので、使いたいものを確認します。このページで必要なパラメータを確認します。
今回は特定のチャンネルのメッセージをとってこようと思うので、[channels.history](https://api.slack.com/methods/channels.history)を利用します。

おっと、期間指定がUNIX時間のようですね。

- [Slack Web API](https://api.slack.com/web)
- [API Methods](https://api.slack.com/methods)

# Shiny側のTips

## パラメータ作成

まず、API側に送りつけるパラメータをlist形式で作成します。

![image](https://qiita-image-store.s3.amazonaws.com/0/83530/d788e9a4-ef31-a39c-fd59-ae60706a3a4c.png)

Shinyの通常の構成としては画面側（ui.R）で入力部品を用意して、その入力の変化をトリガーにロジック側（server.R）の処理を動かします。

例えば、期間指定とトークンとチャンネルIDを受け取って、パラメータを作る場合は

```R:ui.R
# サイドバーのところ
sidebarLayout(
  sidebarPanel(
    dateRangeInput(
      "date_range",
      "範囲選択",
      start = format(Sys.Date()-1, "%Y-%m-%d"),
      end = format(Sys.Date(), "%Y-%m-%d")
    ),
    textInput('token',"トークン"),
    textInput('channel',"チャンネルID")
  ),
  # MainPanel
  mainPanel(
     ###
  )
)
```
```R:server.R
getVal <- function(obj){
  if(is.null(obj) || is.na(obj)){
    return("")
  }else{
    return(obj)
  }
}

endPoint.history <- 'https://slack.com/api/channels.history'

# slackへの送信パラメータ作成
getParams <- reactive({
  oldest = as.numeric(as.POSIXct(as.Date(input$date_range[1])))
  latest = as.numeric(as.POSIXct(as.Date(input$date_range[2])))
  token = input$token
  channel = input$channel
  
  params <- list(
    token = getVal(token),
    channel = getVal(channel),
    count = 1000,
    latest = latest,
    oldest = oldest
  )
  params
})
```
こんな感じ。

UNIX時間に変換する場合はPOSIXct型のものをas.numericで数値にすると大丈夫です。
また、入力を受ける場合reactiveである必要があるのでreactive({})で定義します。

## URLからパラメータ取得

トークンなどをプログラム中に埋め込むのはいやなので、URLに引っ付けれるようにします。
http://xxx/shiny/?token=aaaaa
みたいなページを開くとトークンが設定されるようにしてみます。

URLの情報を取得したい場合は
`session$clientData`から各種情報が取得できます。

?token=aaaaaを取得して、それをセットした状態でテキストボックスを生成するという場合、ui.R側にはuiOutput('name')を用意しておき、サーバー側でtextInput部品を生成します。

```R:ui.R
#    textInput('token',"トークン"),
    uiOutput('tokenOut')
```
```R:server.R
output$tokenOut <- renderUI({
    urlInfo <- parseQueryString(session$clientData$url_search)
    
    textInput('token',"トークン", urlInfo[["token"]])
})
```

* [Shiny from R Studio](http://shiny.rstudio.com/articles/client-data.html)

## APIアクセスとデータ取得

HTTPアクセス周りをサポートしてくれるhttrパッケージを入れておくと便利です。
こちらのPOSTメソッドを使ってアクセスします。上で作成したパラメータを渡して情報を取得します。

```R:server.R
  getSlackData <- reactive({
    params <- getParams()
    
    resp <- POST(endPoint.history, 
                body = params,
                encode = "multipart",
                content_type = "application/x-www-form-urlencoded"
#                ,verbose() # コレつけるとリクエスト・レスポンスの詳細が見れる
                )
    jsonFromSlack <- content(resp, "parsed")
    # 取得した情報がlist形式に得られるのでここから自由に加工
  })
  ```

[[翻訳] httr vignette: httrはやわかり](https://qiita.com/nakamichi/items/14f9952445089927c38e)

このあたりが抑えられれば、あとは通常のR＆Shinyの書き方でグラフやら表やらを作っていくとWebアプリが出来上がりそうです。


とりあえず作ってみているサンプルソースコードは[こちら](https://github.com/stkdev/slack_getter)。

Slackはメッセージ自体に階層構造持たせたりできるので、そのあたりもうまく解析して必要なメッセージが取得できるような汎用性を持たせたい。