【Server Side Swift】VaporでSlack botを作る

# はじめに

Server Side SwiftのwebフレームワークであるVaporのサンプルアプリケーションとして、[Slack bot](https://github.com/vapor/slack-bot)の例があります。
そのリポジトリに倣うと、Swiftでとても簡単に Slack bot が作れたので、その方法を紹介します。


## <i class="fa fa-warning"></i> 事前注意

かなり簡単に作成できた印象で、個人的にはとても面白いのですが、
Vapor自体が日々アップデートをしていっているようなフェーズなため、今回の手順でうまくいかなくなる可能性は大いにあります。
あくまで遊び程度で触るのがいいかなと思います。

## <i class="fa fa-code"></i> サンプルコード

今回作ったサンプルコードはGithub上に上げています。
https://github.com/taji-taji/VaporSampleBot

# <i class="fa fa-trophy"></i> ゴール

- Slackに投稿したメッセージの任意のテキストに反応して発言するSlack botを`Vapor`を使って作成する。
- 上記をHerokuにデプロイして動かす。

# <i class="fa fa-wrench"></i> 筆者実行環境

- OSX: 10.11.6（15G31）
- Swift: DEVELOPMENT-SNAPSHOT-2016-07-25-a
- Vapor Toolbox v0.8.0
- heroku-toolbelt/3.43.9

# 前提

- `vapor`コマンドが使用できること
    - [こちらのドキュメント](https://vapor.github.io/documentation/)を参考に、`vapor`コマンドが使える環境を整えてください。
- Slackアカウントを持っていること
- Herokuのアカウント・Toolbeltを持っていること
    - ローカルmac上で動かすだけなら不要です。

# 1. 準備

## SlackでBot Userを作る

- 以下のURLからBotのアカウントを作成します。
    - https://my.slack.com/services/new/bot

![スクリーンショット 2016-08-21 8.08.46.png](https://qiita-image-store.s3.amazonaws.com/0/11914/4678539e-24f6-ad48-c590-7a96c5a9d051.png)

- 作成が完了すると、Botアカウントの`API Token`が取得できます。あとで使用するので、これをメモっておきます。（メモらなくても後からでも確認できます。）

![スクリーンショット_2016-08-21_8_11_18.png](https://qiita-image-store.s3.amazonaws.com/0/11914/1ce4172e-24b0-afea-c8b9-70970cf31322.png)

# 2. プロジェクトの作成

作業ディレクトリ直下でVaporのアプリケーションのプロジェクトを作成します。

```shell-session
$ vapor new {プロジェクト名}
```


作成したら、プロジェクトの直下に移動します。

```shell-session
$ cd {プロジェクト名}
```


例）筆者の場合

```shell-session
$ vapor new VaporSampleBot
$ cd VaporSampleBot
```


# 3. サンプルアプリのコードをダウンロード

Vaporのサンプルアプリのコードを雛形として使用するため、以下のリポジトリからサンプルアプリのコードをダウンロードし、先ほど作ったプロジェクトにコードを置き換えていきます。

https://github.com/vapor/slack-bot

## Sourceコードの置き換え

2で作成したプロジェクト直下の`App`フォルダ内のファイル・フォルダを全て、ダウンロードしたサンプリアプリのSourceフォルダ内のファイルに置き換えます。

↓のような感じになります。
![スクリーンショット 2016-08-21 15.32.59.png](https://qiita-image-store.s3.amazonaws.com/0/11914/a83caf30-c1d4-38aa-467c-0bc0e8ec19d6.png)


## Packageファイルの変更

次に、2で作成したプロジェクトの`Package.swift`を次のように変更します。

```swift:Package.swift
import PackageDescription

let package = Package(
    name: "VaporSampleBot",
    dependencies: [
        .Package(url: "https://github.com/vapor/tls-provider", majorVersion: 0, minor: 4)
    ],
    exclude: [
        "Config",
        "Database",
        "Localization",
        "Public",
        "Resources",
        "Tests",
    ]
)
```



# 4. 設定ファイルの作成

プロジェクト直下のConfigフォルダの下に`bot-config.json`を作成し、準備の項で取得したSlack botのAPI Tokenを以下のように記述します。

```json:bot-config.json
{
    "token": "xcxb-your-api-key-here",
}
```

ローカルmac上で動かす際には上のように直接文字列としてAPI Tokenを指定すればいいですが、
実際にherokuにデプロイする際には、環境変数として設定するため、次のような記述になります。

```json:bot-config.json
{
    "token": "$BOT_TOKEN",
}
```

### <i class="fa fa-warning"></i> 注意点

mac上で動かす際に、tokenの値を`$BOT_TOKEN`とすると、以下のような設定値が取得できないエラーが出てしまいます。

```
fatal error: Error raised at top level: App.BotError.missingConfig
```


# 5. ローカルで動かしてみる

まず、ビルドしてみましょう。

```shell-session
$ vapor build
Fetching Dependencies [Done]
Building Project [Done]
```

うまくビルドできれば上のようになります。
それでは動かしてみましょう。

```shell-session
$ vapor run
```

うまくつながれば、次のような感じでwssで繋がった様子が表示されるかと思います。

```shell-session
Running VaporSampleBot...
Connected to wss://mpmulti-5..[略]
```

さあ、それではSlackのbotがいるチャンネルかbotユーザーへのダイレクトメッセージで「hello bot!」と発言してみましょう！

![スクリーンショット 2016-08-21 16.22.39.png](https://qiita-image-store.s3.amazonaws.com/0/11914/cd0dd7fd-4081-8b54-8420-628a8f6c41dd.png)


# 6. Herokuへのデプロイ

## Procfileの変更

プロジェクト直下のProcfileを変更します。
「web」から「worker」にすればOKです。

```:Procfile
worker: App --env=production --workdir="./"
```

## Herokuでアプリケーション作成

![スクリーンショット 2016-08-21 12.19.24.png](https://qiita-image-store.s3.amazonaws.com/0/11914/d98f237a-2de5-c919-612f-7d588d4c19a3.png)

## Heroku Git の設定

アプリケーション作成後の画面に従ってこの設定ができるかと思うので、設定を進めてください。

## Herokuの各種設定

### Slack bot の API Token

```shell-session
$ heroku config:set BOT_TOKEN=xoxb-00000000000-XXXXXXXXXXXXXXXXXXXXXXXXX
```

### buildpackの設定

```shell-session
$ heroku buildpacks:set https://github.com/kylef/heroku-buildpack-swift
```

## herokuへpushしてデプロイ

```shell-session
$ git push heroku master
```

デプロイには数分かかります。しばらく待ちましょう。

## dynoをscale

次のコマンドでdynoを起動します。

```shell-session
$ heroku ps:scale worker=1
```

Herokuの管理画面で下のようになっていればOKです。
（画面上に反映されるまで若干のタイムラグがあるかもしれないです。）

![スクリーンショット 2016-08-21 16.54.03.png](https://qiita-image-store.s3.amazonaws.com/0/11914/a4077755-145f-e513-3f20-38b66705eef4.png)

# 7. 動作確認

5でローカルで動作させた時と同様に、Slackのbotがいるチャンネルかbotユーザーへのダイレクトメッセージで「hello bot!」と発言してみましょう！

うまく返事が返って来ればOKです！
お疲れ様でした :smile: 


---

# Advanced

## 反応する言葉や返信内容を変えたい時

おそらくコード見れば分かるので書くまでもないかと思うのですが、、

`App/main.swift`の次の箇所を自分好みに変えていけばいいですね。

```swift:App/main.swift
// ~略~
    ws.onText = { ws, text in
        print("[event] - \(text)")

        let event = try JSON(bytes: text.utf8.array)
        guard
            let channel = event["channel"]?.string,
            let text = event["text"]?.string
            else { return }

        if text.hasPrefix("hello") {
            let response = SlackMessage(to: channel, text: "Hi there 👋")
            try ws.send(response)
        } else if text.hasPrefix("version") {
            let response = SlackMessage(to: channel, text: "Current Version: \(VERSION)")
            try ws.send(response)
        }
    }
// ~略~
```


例えば、次のように変更をすると、

```swift:App/main.swift
// ~略~
    ws.onText = { ws, text in

        let event = try JSON(bytes: text.utf8.array)
        guard
            let channel = event["channel"]?.string,
            let text = event["text"]?.string
            else { return }

        if text.contains("すし") {
            let response = SlackMessage(to: channel, text: "🍣")
            try ws.send(response)
        }
    }
// ~略~
```

このような感じになります。

![スクリーンショット 2016-08-21 19.49.22.png](https://qiita-image-store.s3.amazonaws.com/0/11914/f8a80fd2-fd0f-7b9d-449d-fe04cc19ce6e.png)


## その他

### `bot-config.json`について

4で作成した`bot-config.json`の`token`の値ですが、前述の説明では、
「ローカルで動かす時は値を直接書いて、Herokuにあげる時は `$BOT_TOKEN` と書く」
という説明になっていますが、ローカルのmacでも、環境変数として`BOT_TOKEN`を設定すればコードの書き換えを行うことなくできます。

```shell-session
$ export BOT_TOKEN=xoxb-00000000000-XXXXXXXXXXXXXXXXXXXXXXXXX
```

また、当然ただの環境変数なので`BOT_TOKEN`という名前でなくでも大丈夫です。
ただし、変更する場合はコード上の環境変数を表す文字列とローカル環境・リモート環境（Heroku）の環境変数も変更することを忘れないようにしないといけません。


# <i class="fa fa-external-link"></i> Reference

- Vapor の Docs
    - https://vapor.github.io/documentation/
- Vapor の Slack bot リポジトリ
    - https://github.com/vapor/slack-bot
- Vapor製の Slack bot 「penny」のリポジトリ
    - https://github.com/vapor/penny