R
Slack
Shiny

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

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

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

Slack側の準備

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

トークン取得

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

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

チャンネルIDの取得

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

image

エンドポイントの確認

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

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

Shiny側のTips

パラメータ作成

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

image

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

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

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(
     ###
  )
)
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部品を生成します。

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

    textInput('token',"トークン", urlInfo[["token"]])
})

APIアクセスとデータ取得

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

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はやわかり

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

とりあえず作ってみているサンプルソースコードはこちら

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