go-bindataで実行バイナリにWeb UIをバンドルする〜slackboardの場合〜

個人的にGoはミドルウェアやコマンドラインツールの開発によく利用していますが、その理由の一つにシングルバイナリなのでデプロイが楽、というのがあります。一方で、（特に）サーバ系のミドルウェアだとちょっとしたWeb UIを付けたくなることがあります。こうなると、シングルバイナリのほかにHTMLやCSS、JavaScriptといったリソースファイルが多数付いてくるのでちょっと面倒です。

そこで[go-bindata](https://github.com/jteeuwen/go-bindata)を使って実行バイナリにそれらのリソースファイルをくっつけてしまうという方法があります。go-bindataは各リソースファイルの内容をGoのコードとして生成し、**Asset()**という関数を呼び出すことで内容を取得することができます。

## go-bindataによるコード生成

まずは、go-bindataをインストールします。

```
go get -u github.com/jteeuwen/go-bindata/...
```

続いて今回の題材である[slackboard](https://github.com/cubicdaiya/slackboard)をgit cloneします。

```
git clone https://github.com/cubicdaiya/slackboard.git
```

slackboardはSlackのIncoming Webhooksを利用したプロキシサーバです。↓に実際の活用例についての資料があります。

* [Slackプロキシサーバ〜slackboard〜を利用したメルカリのSlack活用法](http://tech.mercari.com/entry/2015/07/06/141056)
* [Slackboard / Slack proxy server in Go](https://speakerdeck.com/cubicdaiya/slack-proxy-server-in-go)

で、大したことはありませんが、slackboardにはboostrapを利用した至極簡単なWeb UI機能があります。ソースコードのレイアウトはこんな感じです。

```
$ tree slackboard
slackboard/ui
├── css
│   ├── bootstrap.css
│   ├── bootstrap.css.map
│   ├── bootstrap.min.css
│   ├── bootstrap-theme.css
│   ├── bootstrap-theme.css.map
│   └── bootstrap-theme.min.css
├── fonts
│   ├── glyphicons-halflings-regular.eot
│   ├── glyphicons-halflings-regular.svg
│   ├── glyphicons-halflings-regular.ttf
│   └── glyphicons-halflings-regular.woff
├── index.html
└── js
    ├── bootstrap.js
    ├── bootstrap.min.js
    ├── jquery-1.11.2.min.js
    └── npm.js
```

このディレクトリに対してgo-bindataを実行するとbindata.goというファイルが生成されます。`-pkg`にはパッケージ名を指定します。

```
go-bindata -pkg slackboard ./ui/*
```

生成されたbindata.goの先頭部分には取り込まれたリソースファイルの一覧がコメントで書き出されます。

```go
// Code generated by go-bindata.                                                                                                                                                                                                              
// sources:                                                                                                                                                                                                                                   
// ui/css/bootstrap-theme.css                                                                                                                                                                                                                 
// ui/css/bootstrap-theme.css.map                                                                                                                                                                                                             
// ui/css/bootstrap-theme.min.css                                                                                                                                                                                                             
// ui/css/bootstrap.css                                                                                                                                                                                                                       
// ui/css/bootstrap.css.map                                                                                                                                                                                                                   
// ui/css/bootstrap.min.css                                                                                                                                                                                                                   
// ui/fonts/glyphicons-halflings-regular.eot                                                                                                                                                                                                  
// ui/fonts/glyphicons-halflings-regular.svg                                                                                                                                                                                                  
// ui/fonts/glyphicons-halflings-regular.ttf                                                                                                                                                                                                  
// ui/fonts/glyphicons-halflings-regular.woff                                                                                                                                                                                                 
// ui/index.html                                                                                                                                                                                                                              
// ui/js/bootstrap.js                                                                                                                                                                                                                         
// ui/js/bootstrap.min.js                                                                                                                                                                                                                     
// ui/js/jquery-1.11.2.min.js                                                                                                                                                                                                                 
// ui/js/npm.js                                                                                                                                                                                                                               
// DO NOT EDIT!

package slackboard
```

## go-bindataで生成したGoのコードからリソースの内容を取得する

bindata.goには**Asset()**という関数が定義されており、これを利用することでリソースの内容を取得できます。以下は**ui/index.html**の内容を取得する例です。

```go
// バイト配列（リソースの内容）とエラーを返す
bs, err := Asset("ui/index.html")
```

先頭のスラッシュが不要なので、HTTPサーバのURIを通して参照するようなケースではsliceで先頭のスラッシュを切り取ってリソースを取得しましょう。

```go
p := r.URL.Path
bs, err := Asset(p[1:])
```

## slackboardでgo-bindataを導入してみて

元々slackboardのWeb UI機能を利用するにはリソースファイルの配置するのと設定ファイル by TOMLにUIのドキュメントルートを設定する必要がありました。

```ini
# Web UIのドキュメントルート
[ui]
root = "/usr/local/share/slackboard"
```

今はgo-bindataでリソースファイルを実行バイナリにバンドルするようになっているので不要になっています。これでシングルバイナリの世界が実現できました。めでたしめでたし。

ちなみに、slackboardにgo-bindataを導入したのは今年の秋に[みんなのGo言語【現場で使える実践テクニック】](https://www.amazon.co.jp/exec/obidos/ASIN/477418392X)でgo-bindataの実例が紹介されていたのを読んだのがきっかけだったります。