テキトウなyamlの値からswagger spec経由でgoのstruct定義のコードを生成してみる
テキトウなyamlの値からswagger spec経由でgoのstruct定義のコードを生成してみる。
やること
- 素となるデータの例を書く(yaml)
- データからswagger specを生成
- swagger specからコードを生成
以下の様な形で変換が行われる。
config.yaml - json2swagger -> config-spec.yaml - swagger2go -> config/config.go
primitiveな状態
こういう感じ。
# need https://github.com/podhmo/{goaway,dictknife} default: mkdir -p dst config swaggerknife json2swagger --name=config config.yaml --dst dst/config-spec.yaml swagger2go dst/config-spec.yaml --position=config --file=config.go --ref="#/definitions/config" goimports -w config/*.go
素となるデータは以下の様な形式
config.yaml
appconf: endpoint: http://foo.bar.jp/api key: hmm secret: hai
swagger specを生成
swagger specを生成する
$ swaggerknife json2swagger --name=config config.yaml --dst dst/config-spec.yaml
生成されたのは以下のようなもの。
config-spec.yaml
definitions: appconf: type: object properties: endpoint: type: string format: url example: http://foo.bar.jp/api x-go-type: net/url.URL key: type: string example: hmm secret: type: string example: hai required: - endpoint - key - secret config: type: object properties: appconf: $ref: '#/definitions/appconf' required: - appconf
goのコードの生成
以下の様な感じで実行(positionsなどを付けているのはGOPATH以下に生成しないようにするため)
$ swagger2go dst/config-spec.yaml --position=config --file=config.go --ref="#/definitions/config"
以下の様なコードが生成される。validationなどは含まれていない。
package main // Config : type Config struct { Appconf Appconf `json:"appconf"` } // Appconf : type Appconf struct { Endpoint string `json:"endpoint"` Key string `json:"key"` Secret string `json:"secret"` }
別の型(url.URL)に対応したい
別の型(url.URL)に対応したい。やろうと思えばできる。
- json2swagger – swagger specの生成時に(format,x-go-typeを付加する)
- swagger2go – goのコード生成時にx-go-typeを見て利用する型を変更する
swagger specの生成時に情報付加
json2swaggerの --emitter
と --detector
というオプションで利用するオブジェクトを差し替えられる。なので以下の様なコードを用意してやる。
resolve.py
from dictknife.swaggerknife.json2swagger import Detector as _Detector from dictknife.swaggerknife.json2swagger import Emitter as _Emitter class Detector(_Detector): def resolve_type(self, value): if isinstance(value, str) and value.startswith(("http://", "https://")): return "string", "url" return super().resolve_type(value) class Emitter(_Emitter): def make_primitive_schema(self, info): d = super().make_primitive_schema(info) if d.get("format") == "url": d["x-go-type"] = "net/url.URL" return d
そして実行時に --detector="./resolve.py:Detector" --emitter="./resolve.py:Emitter"
を追加してあげる。
すると実行結果などは以下の様に変わる。
diff --git a/daily/20170617/Makefile b/daily/20170617/Makefile index 652840b..ccd3240 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ # need https://github.com/podhmo/{goaway,dictknife} +EXTRA = --detector="./resolve.py:Detector" --emitter="./resolve.py:Emitter" default: mkdir -p dst config - swaggerknife json2swagger --name=config config.yaml > dst/config-spec.yaml + swaggerknife json2swagger ${EXTRA} --name=config config.yaml --dst dst/config-spec.yaml swagger2go dst/config-spec.yaml --position=config --file=config.go --ref="#/definitions/config" goimports -w config/*.go diff --git a/daily/20170617/dst/config-spec.yaml b/daily/20170617/dst/config-spec.yaml index 112e1f3..e29fb54 100644 --- a/daily/20170617/dst/config-spec.yaml +++ b/daily/20170617/dst/config-spec.yaml @@ -4,7 +4,9 @@ definitions: properties: endpoint: type: string + format: url example: http://foo.bar.jp/api + x-go-type: net/url.URL key: type: string example: hmm diff --git a/config/config.go b/config/config.go index 9a00a57..f51bfe8 100644 --- a/config/config.go +++ b/config/config.go @@ -1,5 +1,9 @@ package main +import ( + "net/url" +) + // Config : type Config struct { Appconf Appconf `json:"appconf"` @@ -7,7 +11,7 @@ type Config struct { // Appconf : type Appconf struct { - Endpoint string `json:"endpoint"` - Key string `json:"key"` - Secret string `json:"secret"` + Endpoint url.URL `json:"endpoint"` + Key string `json:"key"` + Secret string `json:"secret"` }
swagger2goは x-go-type
というkeyの情報が存在したらそちらを使うようになっている。なのでnet/urlのURLを使うようなコードが生成される。
おしまい。