GAE/GoでSlackの'/'（スラッシュ）コマンドサーバーを立てる

この記事は [Go Advent Calendar 2015](http://qiita.com/advent-calendar/2015/go) の13日目の記事です。

# はじめに

WebSocketを使ったhubotが圧倒的に流行っていますが、何かしらチャットでbotに話しかけてサーバー側で処理してSlackに結果を返すケースであれば、SlashCommandsのIntegrationで十分こと足ります。

https://api.slack.com/slash-commands

GAE/Goで、このSlashCommandsのサーバーを無料枠内でサクッと作れてしまうのでオススメです。

# 事前準備済み

- Googleアカウント、GCP登録済み
- Slack登録済み
- Go環境構築済み
- GAE/Go開発環境構築済み

# 環境準備

## GoogleCloudPlatformでプロジェクトを作成する

![スクリーンショット 2015-12-09 17.34.14.png](https://qiita-image-store.s3.amazonaws.com/0/40887/d32dc04b-9203-c94a-2467-c534ec8e131c.png)

※プロジェクト名はご自由に設定ください

## Project用意してdeployする

### [github.com/kyokomi/slack-slash-commands](https://github.com/kyokomi/slack-slash-commands)をチェックアウトする。

```
$ git clone https://github.com/kyokomi/slack-slash-commands.git
```

### app.yamlにプロジェクト名を設定

```yaml:src/app.yaml
application: <自分で用意したプロジェクト名>
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

- url: /favicon\.ico
  static_files: assets/favicon.ico
  upload: web/favicon\.ico
  expiration: "14d"
```

### GoogleAppEngineにdeployする

```
$ cd ./slack-slash-commands
$ make install
$ make deploy
```

## SlackのIntegrationでSlashCommandsを追加

Integrationsを開いて `Slash Commands`を選択する。

![スクリーンショット 2015-12-09 17.31.44.png](https://qiita-image-store.s3.amazonaws.com/0/40887/a490fd74-64b6-e6d7-2939-dbdc9b851b39.png)

ひとまずSlack上のスラッシュ呼び出しのコマンドを `/hogecmd`にする。
（これはご自由に設定ください）

![スクリーンショット 2015-12-09 17.32.16.png](https://qiita-image-store.s3.amazonaws.com/0/40887/97db3ad7-b621-a5d0-b654-ed515f1f0fc8.png)

## Autocomplete help textを設定する

- Show this command in the autocomplete listにチェックを入れる
- Descriptionに概要を入れる
- Usage hintに追加する予定のコマンドを入れる（最初は無しでも良い）

![スクリーンショット 2015-12-09 18.25.10.png](https://qiita-image-store.s3.amazonaws.com/0/40887/b049b6c7-0fcf-3507-2f32-fd819b05aa6b.png)

## SlackのIntegration側の設定してSaveする

URLに `https://<プロジェクト名>.appspot.com/v1/cmd`を設定する。
(以下は例）

![スクリーンショット 2015-12-09 17.46.00.png](https://qiita-image-store.s3.amazonaws.com/0/40887/0c07c38f-c504-efc8-55d3-4a2ed4812b93.png)

# Slackで動作を確認してみる

`Slash Commands`に設定したコマンドを入力する。（例だと `/hogecmd echo ふむふむ`）

![aaaaaaaa.png](https://qiita-image-store.s3.amazonaws.com/0/40887/2a20f3b0-e1e3-567a-2fd5-6e5a85030b2d.png)

![スクリーンショット 2015-12-13 0.08.51.png](https://qiita-image-store.s3.amazonaws.com/0/40887/8222dd97-a273-9579-3e83-2bf6188e4500.png)



# 自分でコマンドを追加する

基本的には、[github.com/kyokomi/goslash/plugins/echo](https://github.com/kyokomi/goslash/tree/master/plugins/echo)パッケージを参考にして実装してもらえばOKです。



## AppEngineサーバーの現在時刻を返すプラグインを作る例

```go:src/plugins/time.go
package time

import (
	"time"

	"github.com/kyokomi/goslash/goslash"
	"github.com/kyokomi/goslash/plugins"
)

type plugin struct {
}

func New() plugins.Plugin {
	return &plugin{}
}

func (p *plugin) Do(_ goslash.SlashCommandRequest) goslash.SlashCommandMessage {
	return goslash.NewInChannelMessage(
		time.Now().Format(time.RFC3339),
	)
}
```

- `goslash.NewMessage`だと自分以外のユーザーには見えないメッセージになる
- `goslash.NewInChannelMessage`が自分以外のユーザーにも見えるメッセージになる


```diff:src/main.go
package app

import (
	"net/http"

	"github.com/kyokomi/goslash/goslash"
	"github.com/kyokomi/goslash/plugins"
	"github.com/kyokomi/goslash/plugins/echo"

+	"plugins/time"

	"github.com/unrolled/render"
	"google.golang.org/appengine"
	"google.golang.org/appengine/urlfetch"
)

func init() {
	renderer := render.New(render.Options{})

	slashPlugins := map[string]plugins.Plugin{
		"echo": echo.New(),
+		"time": time.New(),
	}

	http.HandleFunc("/v1/cmd", func(w http.ResponseWriter, r *http.Request) {
		ctx := appengine.NewContext(r)

		req, err := goslash.ParseFormSlashCommandRequest(r)
		if err != nil {
			renderer.JSON(w, http.StatusInternalServerError, err.Error())
			return
		}

		slashCmd := plugins.New(urlfetch.Client(ctx), slashPlugins)

		renderer.Text(w, http.StatusOK, slashCmd.Execute(req))
	})
}
```

上記の改修を行いdeployして、 `/hogecmd time`とSlackに入力してみる。

![スクリーンショット 2015-12-12 20.14.35.png](https://qiita-image-store.s3.amazonaws.com/0/40887/b2b4776e-4b62-6601-11b3-21705525a285.png)

現在時刻を返してくれる。

![スクリーンショット 2015-12-13 0.09.12.png](https://qiita-image-store.s3.amazonaws.com/0/40887/5b83d23a-6c19-147b-7433-4135dd90ff32.png)

※上記の例は、GAE/Goに限定した実装になってますが、[github.com/kyokomi/goslash/plugins/echo](https://github.com/kyokomi/goslash/tree/master/plugins/echo)のように普通のGoライブラリとして実装すれば、GAE/Go以外でも使えます。

# おわり
ちなみにAWSのEC2等（いま動いているAPIサーバー等）でも同様に、SlashCommands用のAPIを生やしてあげれば、サーバーの情報やDBに問い合わせた結果などをSlackのチャットで簡単にとることが可能になりますので、ぜひお試しください。

今回作った[github.com/kyokomi/goslash](https://github.com/kyokomi/goslash)ですが、かなり突貫工事で作ったのでおかしい所や追加したいプラグイン等あれば、お気軽にPRください。