概要
goa は DSL で書かれた API デザインを goa のツールで変換してコードを生成します.
そのコード生成ツールは goagen
です.まずはこれをインストールして,実際に動かしてみるところまで説明します.
生成されるファイルとか,利用する API デザインについてはここでは触れませんが,おいおい説明していきたいと思います.
今回は,goagen
のインストールと使い方の概要までです.
インストール
$ go install github.com/goadesign/goa/goagen
でインストールできます.vendoring する場合は vendor
フォルダに github.com/goadesign/goa
を配置してください.
vendor 以下の goagen フォルダまで降りていってビルドしておきます.
$ cd ./vendor/github.com/goadesign/goa/goagen $ go build $ cd ../../../../../
実行
基本的な使い方
$ goagen <サブコマンド> -d <デザインの配置してあるパッケージパス>
vendoring してるなら
$ ./vendor/github.com/goadesign/goa/goagen <サブコマンド> -d <デザインの配置してあるパッケージパス>
で実行できます.goagen
はリポジトリの goagen
以下の gen_*
というフォルダがサブコマンドに対応していて,実行するたびにプラグイン的にここの下をビルドして利用しているので,goagen
をインストールしたからといってリポジトリを消してしまうとうまく動かなくなってしまうので注意です.
注意
デザインの配置してあるパッケージパスは,$GOPATH/src
からの相対パスを指定する必要があります.
$GOPATH/src/cellar/design
なら,cellar/design
を指定します.
(参考) goa/goagen
以下の構造 :
github.com/goadesign/goa/ ├── goagen/ │ ├── codegen/ │ ├── gen_app/ ← gen_app は app というサブコマンドに対応している │ ├── gen_client/ │ ├── gen_js/ │ ├── gen_main/ │ ├── gen_schema/ │ ├── gen_swagger/ │ ├── meta/ │ └── utils/ (snip...)
とりあえず動かしてみよう!
色々説明するより動かしてみるのが手っ取り早いので動かしてみましょう.
準備
自分の $GOPATH/src
の下に cellar
というフォルダを作ってください.
以下ではこのフォルダで作業することを前提とします.
$ mkdir $GOPATH/src/cellar $ cd $GOPATH/src/cellar
サンプルのAPIデザインを配置します.天下り的に以下の内容を design/desing.go
に保存してください.
これは https://goa.design/learn/guide/ でサンプルとして紹介されているワインセラーを題材にしたAPIサーバの最小のサンプルです.
/bottles/:bottleID
というエンドポイントに管理しているワインのIDをセットすると,ワインの情報が得られるというようなものです.
package design // The convention consists of naming the design // package "design" import ( . "github.com/goadesign/goa/design" // Use . imports to enable the DSL . "github.com/goadesign/goa/design/apidsl" ) var _ = API("cellar", func() { // API defines the microservice endpoint and Title("The virtual wine cellar") // other global properties. There should be one Description("A simple goa service") // and exactly one API definition appearing in Scheme("http") // the design. Host("localhost:8080") }) var _ = Resource("bottle", func() { // Resources group related API endpoints BasePath("/bottles") // together. They map to REST resources for REST DefaultMedia(BottleMedia) // services. Action("show", func() { // Actions define a single API endpoint together Description("Get bottle by id") // with its path, parameters (both path Routing(GET("/:bottleID")) // parameters and querystring values) and payload Params(func() { // (shape of the request body). Param("bottleID", Integer, "Bottle ID") }) Response(OK) // Responses define the shape and status code Response(NotFound) // of HTTP responses. }) }) // BottleMedia defines the media type used to render bottles. var BottleMedia = MediaType("application/vnd.goa.example.bottle+json", func() { Description("A bottle of wine") Attributes(func() { // Attributes define the media type shape. Attribute("id", Integer, "Unique bottle ID") Attribute("href", String, "API href for making requests on the bottle") Attribute("name", String, "Name of wine") Required("id", "href", "name") }) View("default", func() { // View defines a rendering of the media type. Attribute("id") // Media types may have multiple views and must Attribute("href") // have a "default" view. Attribute("name") }) })
コード生成
$ goagen bootstrap -d cellar/design app app/contexts.go app/controllers.go app/hrefs.go app/media_types.go app/user_types.go app/test app/test/bottle_testing.go main.go bottle.go tool/cellar-cli tool/cellar-cli/main.go tool/cli tool/cli/commands.go client client/client.go client/bottle.go client/user_types.go client/media_types.go swagger swagger/swagger.json swagger/swagger.yaml
これで APIサーバのモック,クライアント,swagger ドキュメントが生成されました.
. ├── app │ ├── contexts.go │ ├── controllers.go │ ├── hrefs.go │ ├── media_types.go │ ├── test │ │ └── bottle_testing.go │ └── user_types.go ├── bottle.go ├── client │ ├── bottle.go │ ├── client.go │ ├── media_types.go │ └── user_types.go ├── design │ └── design.go ├── main.go ├── swagger │ ├── swagger.json │ └── swagger.yaml └── tool ├── cellar-cli │ └── main.go └── cli └── commands.go
サーバを動かしてみる
$ go run *.go
でサーバが立ち上がります.立ち上がったサーバは何も意味ある動作しませんが,/bottles/:bottleID
というエンドポイントが出来ているのでここに curl とかでアクセスするとレスポンスがあります.
$ curl -XGET localhost:8080/bottles/1 HTTP/1.1 200 OK Content-Type: application/vnd.goa.example.bottle+json Date: Sun, 11 Sep 2016 04:31:20 GMT Content-Length: 29 {"href":"","id":0,"name":""}
また,クライアントも同時に出来ているので,クライアントをたたけばレスポンスを得られます.
$ go run tool/cellar-cli/main.go show bottle bottles/1 2016/09/11 13:33:50 [INFO] started id=BMdh+bm3 GET=http://localhost:8080/bottles/1 2016/09/11 13:33:50 [INFO] completed id=BMdh+bm3 status=200 time=3.924862ms {"href":"","id":0,"name":""}
goagen サブコマンド
指定できるサブコマンドは以下です.bootstrap は初回にだけ実行するサブコマンドで,main
,app
,client
,swagger
のエイリアスになってます.この辺のコマンドは Makefile 作っておいて実行するのがいいと思います.ここでは触れませんが,main
コマンドで生成されるファイル以外は編集不要なコードです.実際ファイルを見てみると,先頭部分に The content of this file is auto-generated, DO NOT MODIFY と書かれているが分かると思います.
サブコマンド | 説明 |
---|---|
bootstrap | 初回に実施するコマンド (main/app/client/swaggerを実行する) |
main | APIサーバの main とコントローラーを作業ディレクトリに生成.このコマンドで生成されるファイルは上書きされない (--force オプションで上書きを強制可能) |
app | アプリケーションのテンプレートを app ディレクトリ以下に生成 |
client | APIサーバに対応するクライアントのコードを client / tool ディレクトリ以下に生成 |
swagger | APIサーバの使用を swagger 形式で swagger ディレクトリ以下に出力 |
js | JavaScript のAPIサーバクライアントを js ディレクトリ以下に生成 |
schema | API の JSON スキーマを schema ディレクトリに生成 |
gen | サードパーティの generator を利用するときに指定する.gorma とか使いたいときに利用 |