goa には静的ファイル配信のための DSL として Files が用意されており、以下のような定義を行うと FileServer を生成してくれます。
Files("/swagger/*filepath", "public/swagger/")
生成される FileServer
は http.FileSystem という interface を通してファイルオープンを行うのですが、従来は http.Dir という実装を固定で使う仕様になっていました。 http.Dir
は実行環境のネイティブファイルシステムからファイルオープンを行います。これは、ビルドしたバイナリを実行環境にデプロイする際に Files
で定義した静的ファイルもそのファイルシステム上に配置する必要がある、ということを意味します。
Go は、ビルドしたバイナリひとつをデプロイすれば動作する、いわゆるシングルバイナリが魅力のひとつですが、 goa の FileServer
でそれを実現するためには http.Dir
以外の http.FileSystem
実装を使えた方が都合がいいです。という訳で変更できるようにしました。
使い方は簡単です。例として go-bindata を使って実装してみましょう。あらかじめ go-bindata
で目的の静的ファイルを Go のソースコード化しておき、該当の controller をマウントする前にそのコードを使用するよう FileSystem
というフィールドを差し替えます。
c1 := controllers.NewSwaggerController(service) c1.FileSystem = func(dir string) http.FileSystem { return &assetfs.AssetFS{ Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: dir, } } app.MountSwaggerController(service, c1)
go-bindata
で生成されたコードを http.FileSystem
にラップするライブラリとして go-bindata-assetfs を使用しています。これで該当の静的ファイルは Go の内部でオープンされるようになるのでデプロイする必要がなくなります。ちなみに、記事のタイトルと例では go-bindata
を取り上げましたが、 FileSystem
フィールドの関数は http.FileSystem
を返せば良いので他のライブラリを使うこともできます。
より詳細な例は以下をご覧ください。