openapi-generator-cli とは?
openapi-generator-cliは、OpenAPIで書かれた仕様書からコードを生成するものです。
特にGo言語用というわけではなく、WebApplicationFrameworkに従ったコードも生成してくれます。どんな言語、Frameworkに対応しているかは、READMEのOverviewを見てみると良いでしょう。Perlもありますね(ないと思ってた)。
今回、WebApplicationFrameworkにFiberを使ったのですが、残念ながら、Fiberには対応していません。ですが、生成したコードを使うことは出来ます。
openapi-cli-generatorを動かす
今回は、Dockerで動かしました。openapi-generator-cliのオプションとしては、generate
から後ろですが、オプションが多いですね。
docker run --rm -u "${UID}:${GID}" -v "${PWD}:/local" \
openapitools/openapi-generator-cli generate -g go \
--skip-validate-spec \
--global-property models,supportingFiles,modelDocs \
--additional-properties withGoMod=false \
--package-name package名 \
-i /local/docs/openapi/openapi.json \
-o /local/internal/interfaces/api/generated/package名/
一つずつ見ていきましょう。
-
generate
... コードを生成する。そのままです。以下は generateのオプションです -
-g go
... Go用のコードを生成する -
--skip-validate-spec
... 仕様書の書式のチェックをスキップ -
--global-property models,supportingFiles,modelDocs
... models,supportingFiles,modelDocsを生成する -
--additional-properties withGoMod=false
... go.mod を作らない -
--package-name package名
... package名を指定する -
-i /local/docs/openapi/openapi.json
... 仕様書を指定する -
-o /local/internal/interfaces/api/generated/package名/
... 出力先の指定(/localに、current directoryをmountしています)
--global-property
を指定しないと、生成したコードをそのまま使えませんでした。今回使用する用途的に必要そうな最低限の組み合わせになります(modelDocsは別に不要ですが)。
生成されたコードを使う
openapi-generator-cliが生成するのは、主に、
-
client.go
... APIを叩くためのコード -
configuration.go
... エンドポイントのURL等の設定っぽい -
model_*パス_request.go
... 各APIのリクエストに関する型や実装 -
model_*パス_response.go
... 各APIのレスポンスに関する型や実装
GET
で使え...ません。GETのAPIに関しては、model_*パス*request.go
が存在しないので、fiberのQueryParser
に渡せません。
--global-property
に apis
を渡せば、api_*.go
にGETようの型は作ってくれるのですが、構造体のメンバがprivateなので、FiberのQueryParser
に渡すことができません。残念。
コードを参考にして、構造体を作れば楽なのは楽かもしれません。
POST
model_*パス*request.go
の中にJSON用の構造体が入っていますので、それが使えます。例えば、こんな感じですね。
type YourApiRequest struct {
UserID string `json:"user_id"`
}
fiber
のBodyParser
にそのまま渡すことが出来ます。
c.BodyParser(req)
レスポンス
model_*パス*response.go
の中にJSON用の構造体が入っていますので、それが使えます。例えば、こんな感じですね。
type YourApiNameGet200Response struct {
Result []YourApiNameGet200ResponseResultInner `json:"result"`
}
この型通りにデータを作ってやって、JSONにすれば、そのままレスポンスに使えます。
data := YourApiNameGet200ResponseResultInner{
// 略
}
c.JSON(your_pacakge.NewYourApiResponse(data))
各POSTの型にダミーのメソッドを作る
codegen/openapi-request-generator.sh
というプログラムで、CanWrap
というメソッドを各作ります。やってることは、以下のように超単純です。
#!/bin/bash
dirs=$1
if [ "$dirs" = "" ]; then
dirs="your_pacakge_name"
fi
for dir in $dirs; do
echo -e "package $dir\n" > internal/interfaces/api/generated/$dir/generated_func.go;
grep 'Request struct' -r internal/interfaces/api/generated/$dir | grep type |cut -d ' ' -f 2 | sort | xargs -I {} echo "func (*{}) CanWrap() { }" >> internal/interfaces/api/generated/$dir/generated_func.go
go fmt internal/interfaces/api/generated/$dir/generated_func.go
done
各Postリクエストの型に対して、CanWrap
という何もしないメソッドを定義しています。CanWrap()
は、RequestWrapper
interfaceを満たすためのメソッドです。
type RequestWrapper interface {
CanWrap()
}
これで何が嬉しいかと言うと...前回書いたやつが、できるようになりますね。
以下、略。
終わり
以上、openapi-generator-cli を使えば、楽できますよという話でした。